SearchSoftware Public API
v4.0.0Contact: support@sres.nl
https://api.searchsoftware.nlProductionThe SearchSoftware Public API is a REST interface for managing records in your SearchSoftware environment from external integrations.
Authentication
Every request must include a valid API key. Two transport mechanisms are accepted (either is sufficient):
Authorization: Bearer <api-key>header (recommended)?api_key=<api-key>query parameter
API keys are scoped — each key grants one or more <resource>:<action> tokens. A key missing the required scope receives 403.
| Scope | Grants |
|---|---|
people:read | Read people |
people:write | Create / update people |
companies:read | Read companies |
companies:write | Create / update companies |
jobs:read | Read jobs |
jobs:write | Create / update jobs |
files:read | Download files (also needs the record's read scope) |
files:write | Reserved for future file write access |
sources:read | Read sources |
sources:write | Create / update sources and source groups |
workflows:read | Read workflow phases and stages |
workflows:write | Set workflow phase on a record |
users:read | Read users |
users:write | Create / update users |
communications:read | Read communications and methods |
communications:write | Create communications and methods |
comments:read | Read comments |
comments:write | Create comments |
notes:read | Read notes |
notes:write | Create notes |
categories:read | Read categories and category groups |
categories:write | Create / update categories and category groups |
work_history:read | Read work history entries |
work_history:write | Create / update work history entries |
todos:read | Read todos, todo boards, board lists, and labels |
todos:write | Create / update todos, todo boards, board lists, and labels |
Wildcard grants: *, *:*, *:read, *:write, and <resource>:*. write implicitly grants read for the same resource.
IDs
All record identifiers are opaque strings. Treat them as opaque tokens.
Response envelope
Success:
{ "status": "ok", "data": <payload> }Error:
{ "status": "error", "error": { "code": "INVALID_ID", "status_code": 400, "message": "Invalid id" } }Common error codes: INVALID_ID, INVALID_BODY, INVALID_API_KEY, FORBIDDEN, NOT_FOUND, VALIDATION_FAILED, INTERNAL_ERROR.
Status defaults in examples: 400 INVALID_ID/INVALID_BODY, 401 INVALID_API_KEY, 403 FORBIDDEN, 404 NOT_FOUND, 422 VALIDATION_FAILED, 500 INTERNAL_ERROR.
?include=
GET endpoints accept an include query parameter — a comma-separated list of related objects to embed under data.objects.
| Resource | Available includes |
|---|---|
| people | primary_email, primary_phone, primary_location, source, notes, flow |
| companies | primary_email, primary_phone, primary_location, source, notes, flow |
| jobs | primary_location, source, notes, flow, company |
Unknown includes are silently ignored.
flow embeds the record's workflow flow status (its phase_status_id references the workflow phase objects from the workflows endpoints). company (jobs only) embeds the job's company (name, image_url, timestamps).
Single-object includes (primary_email, primary_phone, primary_location, source) use a JSON:API-style envelope:
{ "id": "abc123", "type": "source", "attributes": { "name": "LinkedIn" } }notes is different from other includes: it returns an array (up to 25 items), newest-first, instead of a single object or null.
?values=true
Record list, get, and get-many endpoints accept values=true to add a per-item values object. values is keyed by the item's own attributes fields and hydrates reference ids/tokens into public object summaries. This is separate from include and does not add a top-level objects map.
Versioning
The current major version is v4, mounted at /v4.
Authentication
bearer_authhttpAPI key in Authorization header
Scheme: bearer
apikey_authapiKeyAPI key in query string
API Key: api_key in query
People
Person records: create, read, source assignment, workflow updates, and file/image upload.
List people
Returns a paginated list of people records, newest first. Requires people:read.
Primary email, phone, and address are always included in attributes. current_company and current_position are always returned as nullable attributes derived from the current work-history entry. birthdate is always returned as a nullable YYYY-MM-DD attribute. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). Use include for additional sideloads.
Parameters
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
sort_orderstringquerySort by created_at: asc or desc (default desc)
includestringqueryOptional includes: primary_email, primary_phone, primary_location, source, notes, flow
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
People list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people'const response = await fetch('https://api.searchsoftware.nl/v4/records/people', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a person
Creates a person record. Requires people:write.
name and email_address are required. A person with an existing email address is rejected. Create can set custom fields in the same format as PATCH.
Body
namestringrequiredFull name
email_addressstringrequiredPrimary email address
phone_numberstringPhone number
work_titlestringWork title
company_idstringcompany ID
assigned_tostringuser ID to assign the person to
created_bystringuser ID of the record creator
assigned_bystringuser ID of the assigner
genderstringGender
workflow_idstringworkflow ID to attach on creation
workflow_phase_idstringWorkflow phase ID to place the new person in. Requires workflow_id. Must belong to that workflow. Defaults to the first phase when omitted.
streetstringStreet address
zipstringPostal or ZIP code
citystringCity
country_codestringISO country code
birthdatestringBirthdate in YYYY-MM-DD format
primary_document_idstringfile ID for the primary document
typesarrayArray of person type string identifiers (e.g. ["candidate", "contact"])
custom_fieldsobjectObject keyed by custom-field slug. Values may be strings, numbers, booleans, arrays, objects, or null. Image/file custom fields are read as image:<sqid> / file:<sqid> reference tokens and may be written with a linked object sqid or matching token.
Response
Person created
Invalid request body
Invalid API key
Insufficient scope
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/people' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
}
response = requests.post('https://api.searchsoftware.nl/v4/records/people', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/people", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
});
let response = client.post("https://api.searchsoftware.nl/v4/records/people")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"email_address": "string",
"phone_number": "string",
"work_title": "string",
"company_id": "string",
"assigned_to": "string",
"created_by": "string",
"assigned_by": "string",
"gender": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"street": "string",
"zip": "string",
"city": "string",
"country_code": "string",
"birthdate": "string",
"primary_document_id": "string",
"types": [],
"custom_fields": {}
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get people by IDs
Fetches multiple person records by ID in one request. current_company and current_position are always returned as nullable attributes derived from the current work-history entry. birthdate is always returned as a nullable YYYY-MM-DD attribute. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). Requires people:read.
Send up to 100 IDs in ids. Only existing, visible records are returned; unknown IDs are silently omitted. Result order is not guaranteed to match request order; match results by their id.
Body
idsarrayrequiredArray of record IDs to fetch (max 100)
Parameters
includestringqueryOptional includes: source, notes, flow
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Get people by IDs results
Invalid id in request body
Invalid API key
Insufficient scope
Too many ids or invalid request body
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X POST 'https://api.searchsoftware.nl/v4/records/people/get-many' \
-H 'Content-Type: application/json' \
-d '{
"ids": []
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/get-many', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": []
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"ids": []
}
response = requests.post('https://api.searchsoftware.nl/v4/records/people/get-many', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/get-many')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"ids": []
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"ids": []
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/people/get-many", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/get-many');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"ids": []
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"ids": []
});
let response = client.post("https://api.searchsoftware.nl/v4/records/people/get-many")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"ids": []
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a person
Fetches one person by ID. current_company and current_position are always returned as nullable attributes derived from the current work-history entry. birthdate is always returned as a nullable YYYY-MM-DD attribute. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). Requires people:read.
Parameters
idstringrequiredpathPerson ID
includestringqueryOptional includes: primary_email, primary_phone, primary_location, source, notes, flow
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Person found
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update a person
Updates a record name and/or custom field values addressed by field slug. Requires people:write.
Send name, custom_fields, or both. custom_fields keys must match the field slug exposed on reads; JSON null clears a value.
Body
namestringNew record name. For jobs this updates the title.
custom_fieldsobjectCustom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.
Parameters
idstringrequiredpathPerson ID
Response
Record updated
Invalid id or request body
Invalid API key
Insufficient scope
Record not found
No changes, invalid name, unknown field, or validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/records/people/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "Jane Doe",
"custom_fields": {}
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Jane Doe",
"custom_fields": {}
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "Jane Doe",
"custom_fields": {}
}
response = requests.patch('https://api.searchsoftware.nl/v4/records/people/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "Jane Doe",
"custom_fields": {}
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "Jane Doe",
"custom_fields": {}
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/records/people/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "Jane Doe",
"custom_fields": {}
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "Jane Doe",
"custom_fields": {}
});
let response = client.patch("https://api.searchsoftware.nl/v4/records/people/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "Jane Doe",
"custom_fields": {}
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List jobs for a person
Returns jobs where the person is a candidate, ordered newest first. Requires people:read.
active_candidate_count and rejected_candidate_count are always returned as non-null integers; both are 0 when the job has no candidates. A person is linked to a job by being added as a candidate (job_candidates table).
Parameters
idstringrequiredpathPerson ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Jobs list
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}/jobs'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/jobs', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}/jobs')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/jobs')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}/jobs", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/jobs');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}/jobs")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set person source
Assigns a source to a person. Requires people:write.
Body
source_idstringrequiredSource ID
Parameters
idstringrequiredpathPerson ID
Response
Source set
Invalid id or body
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X PUT 'https://api.searchsoftware.nl/v4/records/people/{id}/source' \
-H 'Content-Type: application/json' \
-d '{
"source_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/source', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"source_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"source_id": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/records/people/{id}/source', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/source')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"source_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"source_id": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/records/people/{id}/source", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/source');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"source_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"source_id": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/records/people/{id}/source")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"source_id": "string"
}{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"source_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set person workflow phase
Sets a workflow phase on a person. Requires people:write.
Body
workflow_idstringrequiredWorkflow ID
phase_status_idstringrequiredPhase status ID
notestringOptional note
Parameters
idstringrequiredpathPerson ID
Response
Workflow phase set
Invalid id or body
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X PUT 'https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase' \
-H 'Content-Type: application/json' \
-d '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"workflow_id": "vM7Lp2q",
"phase_status_id": "vM7Lp2q",
"log_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List aliases for a person
Returns all aliases attached to the person. Requires people:read.
Parameters
idstringrequiredpathPerson ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Alias list
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}/aliases'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/aliases', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}/aliases')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/aliases')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}/aliases", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/aliases');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}/aliases")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add an alias to a person
Creates a new alias for the person. Duplicate aliases for the same person are rejected (case-insensitive). Requires people:write.
Body
aliasstringrequiredAlias text
Parameters
idstringrequiredpathPerson ID
Response
Alias created
Invalid id or body
Invalid API key
Insufficient scope
Person not found
Validation failed or duplicate alias
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/people/{id}/aliases' \
-H 'Content-Type: application/json' \
-d '{
"alias": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/aliases', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"alias": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"alias": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/people/{id}/aliases', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/aliases')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"alias": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"alias": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/people/{id}/aliases", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/aliases');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"alias": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"alias": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/people/{id}/aliases")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"alias": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete an alias from a person
Removes an alias from the person. Requires people:write.
Parameters
idstringrequiredpathPerson ID
alias_idstringrequiredpathAlias ID
Response
Alias deleted
Invalid id
Invalid API key
Insufficient scope
Person or alias not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"alias_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List bookmarks for a person
Returns all bookmarks linked to the person. Requires people:read.
Parameters
idstringrequiredpathPerson ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Bookmark list
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add a bookmark to a person
Creates a new bookmark linked to the person. Requires people:write.
Body
urlstringrequiredBookmark URL
titlestringBookmark title
commentstringOptional comment
Parameters
idstringrequiredpathPerson ID
Response
Bookmark created
Invalid id or body
Invalid API key
Insufficient scope
Person not found
Validation failed
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks' \
-H 'Content-Type: application/json' \
-d '{
"url": "string",
"title": "string",
"comment": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "string",
"title": "string",
"comment": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"url": "string",
"title": "string",
"comment": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"url": "string",
"title": "string",
"comment": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"url": "string",
"title": "string",
"comment": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"url": "string",
"title": "string",
"comment": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"url": "string",
"title": "string",
"comment": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"url": "string",
"title": "string",
"comment": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete a bookmark from a person
Removes a bookmark from the person. Requires people:write.
Parameters
idstringrequiredpathPerson ID
bookmark_idstringrequiredpathBookmark ID
Response
Bookmark deleted
Invalid id
Invalid API key
Insufficient scope
Person or bookmark not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"bookmark_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List categories for a person
Returns the categories linked to the person. Requires people:read.
Parameters
idstringrequiredpathPerson ID
limitstringqueryMax results, 1-100, default 50
offsetstringqueryZero-based offset, default 0
Response
Category list
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}/categories'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/categories', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}/categories')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/categories')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}/categories", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/categories');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}/categories")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add a category to a person
Links an existing category to the person. Additive and idempotent: re-linking the same category is a no-op and does not disturb the person's other categories. Requires people:write.
Body
category_idstringrequiredCategory ID to link
Parameters
idstringrequiredpathPerson ID
Response
Category linked
Invalid id or body
Invalid API key
Insufficient scope
Person or category not found
Validation failed
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/people/{id}/categories' \
-H 'Content-Type: application/json' \
-d '{
"category_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/categories', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"category_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"category_id": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/people/{id}/categories', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/categories')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"category_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"category_id": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/people/{id}/categories", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/categories');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"category_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"category_id": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/people/{id}/categories")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"category_id": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Remove a category from a person
Unlinks a category from the person. Idempotent: removing a category that is not linked is a success no-op. Requires people:write.
Parameters
idstringrequiredpathPerson ID
category_idstringrequiredpathCategory ID
Response
Category unlinked
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"category_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List files for a person
Lists files attached to a person. Requires people:read.
Parameters
idstringrequiredpathPerson ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Files list
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}/files'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/files', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}/files')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/files')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}/files", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/files');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}/files")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "file",
"attributes": {
"name": "CV John Doe",
"filename": "abc123_cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List images for a person
Lists images attached to a person. Requires people:read.
Parameters
idstringrequiredpathPerson ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Images list
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}/images'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/images', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}/images')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/images')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}/images", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/images');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}/images")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "image",
"attributes": {
"name": "Headshot",
"filename": "abc123_headshot.jpg",
"mime": "image/jpeg",
"size": 204800,
"width": 400,
"height": 400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List communications for a person
Lists communications attached to a person. Requires people:read.
Parameters
idstringrequiredpathPerson ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
includestringqueryOptional includes: method
Response
Communications list
Invalid id
Invalid API key
Insufficient scope
Person not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:read
apikey_authapiKey in queryAPI key in query string
Scopes: people:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/people/{id}/communications'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/communications', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/people/{id}/communications')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/communications')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/people/{id}/communications", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/communications');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/people/{id}/communications")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Upload a file to a person
Uploads a file to a person using multipart/form-data. Include file as binary data and optional primary_document ("true" or "false") to set primary_document_id.
Body
filestring<binary>requiredFile binary data
primary_documentstringSet to "true" to update primary document
Parameters
idstringrequiredpathPerson ID
Response
File uploaded
Invalid id or no file provided
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/people/{id}/files/upload' \
-H 'Content-Type: multipart/form-data' \
-d '{
"file": "<binary>",
"primary_document": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/files/upload', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"primary_document": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"file": "<binary>",
"primary_document": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/people/{id}/files/upload', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/files/upload')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'
request.body = '{
"file": "<binary>",
"primary_document": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"file": "<binary>",
"primary_document": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/people/{id}/files/upload", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/files/upload');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"file": "<binary>",
"primary_document": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"file": "<binary>",
"primary_document": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/people/{id}/files/upload")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"file": "<binary>",
"primary_document": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Upload an image to a person
Uploads an image to a person using multipart/form-data. Include file as binary data and optional profile_picture ("true" or "false") to set image_id.
Body
filestring<binary>requiredImage binary data
profile_picturestringSet to "true" to update profile picture
Parameters
idstringrequiredpathPerson ID
Response
Image uploaded
Invalid id or no file provided
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: people:write
apikey_authapiKey in queryAPI key in query string
Scopes: people:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/people/{id}/images/upload' \
-H 'Content-Type: multipart/form-data' \
-d '{
"file": "<binary>",
"profile_picture": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/people/{id}/images/upload', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"profile_picture": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"file": "<binary>",
"profile_picture": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/people/{id}/images/upload', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/people/{id}/images/upload')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'
request.body = '{
"file": "<binary>",
"profile_picture": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"file": "<binary>",
"profile_picture": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/people/{id}/images/upload", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/people/{id}/images/upload');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"file": "<binary>",
"profile_picture": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"file": "<binary>",
"profile_picture": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/people/{id}/images/upload")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"file": "<binary>",
"profile_picture": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "headshot.jpg",
"mime": "image/jpeg",
"size": 204800
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Companies
Company records: create, read, source assignment, workflow updates, and file/image upload.
List companies
Returns a paginated list of company records, newest first. Requires companies:read.
Primary email, phone, and address are always included in attributes. active_job_count is always returned as a non-null integer; it is 0 when the company has no active jobs. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). Use include for additional sideloads.
Parameters
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
sort_orderstringquerySort by created_at: asc or desc (default desc)
includestringqueryOptional includes: primary_email, primary_phone, primary_location, source, notes, flow
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Companies list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a company
Creates a company record. Requires companies:write. Create can set custom fields in the same format as PATCH.
Body
namestringrequiredCompany name
created_bystringuser ID of the record creator
assigned_tostringuser ID to assign the company to
assigned_bystringuser ID of the assigner
workflow_idstringworkflow ID to attach on creation
workflow_phase_idstringWorkflow phase ID to place the new company in. Requires workflow_id. Must belong to that workflow. Defaults to the first phase when omitted.
primary_document_idstringfile ID for the primary document
custom_fieldsobjectObject keyed by custom-field slug. Values may be strings, numbers, booleans, arrays, objects, or null. Image/file custom fields are read as image:<sqid> / file:<sqid> reference tokens and may be written with a linked object sqid or matching token.
Response
Company created
Invalid request body
Invalid API key
Insufficient scope
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/companies' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}
response = requests.post('https://api.searchsoftware.nl/v4/records/companies', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/companies", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
});
let response = client.post("https://api.searchsoftware.nl/v4/records/companies")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get companies by IDs
Fetches multiple company records by ID in one request. active_job_count is always returned as a non-null integer; it is 0 when the company has no active jobs. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). Requires companies:read.
Send up to 100 IDs in ids. Only existing, visible records are returned; unknown IDs are silently omitted. Result order is not guaranteed to match request order; match results by their id.
Body
idsarrayrequiredArray of record IDs to fetch (max 100)
Parameters
includestringqueryOptional includes: source, notes, flow
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Get companies by IDs results
Invalid id in request body
Invalid API key
Insufficient scope
Too many ids or invalid request body
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X POST 'https://api.searchsoftware.nl/v4/records/companies/get-many' \
-H 'Content-Type: application/json' \
-d '{
"ids": []
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/get-many', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": []
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"ids": []
}
response = requests.post('https://api.searchsoftware.nl/v4/records/companies/get-many', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/get-many')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"ids": []
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"ids": []
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/companies/get-many", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/get-many');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"ids": []
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"ids": []
});
let response = client.post("https://api.searchsoftware.nl/v4/records/companies/get-many")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"ids": []
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a company
Fetches one company by ID. active_job_count is always returned as a non-null integer; it is 0 when the company has no active jobs. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). Requires companies:read.
Parameters
idstringrequiredpathCompany ID
includestringqueryOptional includes: primary_email, primary_phone, primary_location, source, notes, flow
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Company found
Invalid id
Invalid API key
Insufficient scope
Company not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update a company
Updates a record name and/or custom field values addressed by field slug. Requires companies:write.
Send name, custom_fields, or both. custom_fields keys must match the field slug exposed on reads; JSON null clears a value.
Body
namestringNew record name. For jobs this updates the title.
custom_fieldsobjectCustom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.
Parameters
idstringrequiredpathCompany ID
Response
Record updated
Invalid id or request body
Invalid API key
Insufficient scope
Record not found
No changes, invalid name, unknown field, or validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/records/companies/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "Jane Doe",
"custom_fields": {}
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Jane Doe",
"custom_fields": {}
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "Jane Doe",
"custom_fields": {}
}
response = requests.patch('https://api.searchsoftware.nl/v4/records/companies/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "Jane Doe",
"custom_fields": {}
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "Jane Doe",
"custom_fields": {}
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/records/companies/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "Jane Doe",
"custom_fields": {}
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "Jane Doe",
"custom_fields": {}
});
let response = client.patch("https://api.searchsoftware.nl/v4/records/companies/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "Jane Doe",
"custom_fields": {}
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List jobs for a company
Returns jobs belonging to a company, ordered newest first. active_candidate_count and rejected_candidate_count are always returned as non-null integers; both are 0 when the job has no candidates. Requires companies:read.
Parameters
idstringrequiredpathCompany ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Jobs list
Invalid id
Invalid API key
Insufficient scope
Company not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies/{id}/jobs'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/jobs', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies/{id}/jobs')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/jobs')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies/{id}/jobs", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/jobs');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies/{id}/jobs")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set company source
Assigns a source to a company. Requires companies:write.
Body
source_idstringrequiredSource ID
Parameters
idstringrequiredpathCompany ID
Response
Source set
Invalid id or body
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X PUT 'https://api.searchsoftware.nl/v4/records/companies/{id}/source' \
-H 'Content-Type: application/json' \
-d '{
"source_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/source', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"source_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"source_id": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/records/companies/{id}/source', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/source')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"source_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"source_id": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/records/companies/{id}/source", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/source');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"source_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"source_id": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/records/companies/{id}/source")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"source_id": "string"
}{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"source_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set company workflow phase
Sets a workflow phase on a company. Requires companies:write.
Body
workflow_idstringrequiredWorkflow ID
phase_status_idstringrequiredPhase status ID
notestringOptional note
Parameters
idstringrequiredpathCompany ID
Response
Workflow phase set
Invalid id or body
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X PUT 'https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase' \
-H 'Content-Type: application/json' \
-d '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"workflow_id": "vM7Lp2q",
"phase_status_id": "vM7Lp2q",
"log_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List aliases for a company
Returns all aliases attached to the company. Requires companies:read.
Parameters
idstringrequiredpathCompany ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Alias list
Invalid id
Invalid API key
Insufficient scope
Company not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies/{id}/aliases'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies/{id}/aliases", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies/{id}/aliases")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add an alias to a company
Creates a new alias for the company. Duplicate aliases for the same company are rejected (case-insensitive). Requires companies:write.
Body
aliasstringrequiredAlias text
Parameters
idstringrequiredpathCompany ID
Response
Alias created
Invalid id or body
Invalid API key
Insufficient scope
Company not found
Validation failed or duplicate alias
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/companies/{id}/aliases' \
-H 'Content-Type: application/json' \
-d '{
"alias": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"alias": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"alias": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"alias": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"alias": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/companies/{id}/aliases", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"alias": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"alias": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/companies/{id}/aliases")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"alias": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete an alias from a company
Removes an alias from the company. Requires companies:write.
Parameters
idstringrequiredpathCompany ID
alias_idstringrequiredpathAlias ID
Response
Alias deleted
Invalid id
Invalid API key
Insufficient scope
Company or alias not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"alias_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List bookmarks for a company
Returns all bookmarks linked to the company. Requires companies:read.
Parameters
idstringrequiredpathCompany ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Bookmark list
Invalid id
Invalid API key
Insufficient scope
Company not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add a bookmark to a company
Creates a new bookmark linked to the company. Requires companies:write.
Body
urlstringrequiredBookmark URL
titlestringBookmark title
commentstringOptional comment
Parameters
idstringrequiredpathCompany ID
Response
Bookmark created
Invalid id or body
Invalid API key
Insufficient scope
Company not found
Validation failed
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks' \
-H 'Content-Type: application/json' \
-d '{
"url": "string",
"title": "string",
"comment": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "string",
"title": "string",
"comment": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"url": "string",
"title": "string",
"comment": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"url": "string",
"title": "string",
"comment": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"url": "string",
"title": "string",
"comment": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"url": "string",
"title": "string",
"comment": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"url": "string",
"title": "string",
"comment": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"url": "string",
"title": "string",
"comment": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete a bookmark from a company
Removes a bookmark from the company. Requires companies:write.
Parameters
idstringrequiredpathCompany ID
bookmark_idstringrequiredpathBookmark ID
Response
Bookmark deleted
Invalid id
Invalid API key
Insufficient scope
Company or bookmark not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"bookmark_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List files for a company
Lists files attached to a company. Requires companies:read.
Parameters
idstringrequiredpathCompany ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Files list
Invalid id
Invalid API key
Insufficient scope
Company not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies/{id}/files'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/files', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies/{id}/files')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/files')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies/{id}/files", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/files');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies/{id}/files")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "file",
"attributes": {
"name": "CV John Doe",
"filename": "abc123_cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List images for a company
Lists images attached to a company. Requires companies:read.
Parameters
idstringrequiredpathCompany ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Images list
Invalid id
Invalid API key
Insufficient scope
Company not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies/{id}/images'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/images', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies/{id}/images')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/images')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies/{id}/images", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/images');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies/{id}/images")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "image",
"attributes": {
"name": "Headshot",
"filename": "abc123_headshot.jpg",
"mime": "image/jpeg",
"size": 204800,
"width": 400,
"height": 400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List communications for a company
Lists communications attached to a company. Requires companies:read.
Parameters
idstringrequiredpathCompany ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
includestringqueryOptional includes: method
Response
Communications list
Invalid id
Invalid API key
Insufficient scope
Company not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:read
apikey_authapiKey in queryAPI key in query string
Scopes: companies:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/companies/{id}/communications'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/communications', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/companies/{id}/communications')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/communications')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/companies/{id}/communications", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/communications');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/companies/{id}/communications")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Upload a file to a company
Uploads a file to a company using multipart/form-data. Include file as binary data and optional primary_document ("true" or "false") to set primary_document_id.
Body
filestring<binary>requiredFile binary data
primary_documentstringSet to "true" to update primary document
Parameters
idstringrequiredpathCompany ID
Response
File uploaded
Invalid id or no file provided
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload' \
-H 'Content-Type: multipart/form-data' \
-d '{
"file": "<binary>",
"primary_document": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"primary_document": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"file": "<binary>",
"primary_document": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'
request.body = '{
"file": "<binary>",
"primary_document": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"file": "<binary>",
"primary_document": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"file": "<binary>",
"primary_document": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"file": "<binary>",
"primary_document": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"file": "<binary>",
"primary_document": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Upload an image to a company
Uploads an image to a company using multipart/form-data. Include file as binary data and optional profile_picture ("true" or "false") to set image_id.
Body
filestring<binary>requiredImage binary data
profile_picturestringSet to "true" to update profile picture
Parameters
idstringrequiredpathCompany ID
Response
Image uploaded
Invalid id or no file provided
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: companies:write
apikey_authapiKey in queryAPI key in query string
Scopes: companies:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload' \
-H 'Content-Type: multipart/form-data' \
-d '{
"file": "<binary>",
"profile_picture": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"profile_picture": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"file": "<binary>",
"profile_picture": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'
request.body = '{
"file": "<binary>",
"profile_picture": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"file": "<binary>",
"profile_picture": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"file": "<binary>",
"profile_picture": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"file": "<binary>",
"profile_picture": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"file": "<binary>",
"profile_picture": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "headshot.jpg",
"mime": "image/jpeg",
"size": 204800
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Jobs
Job records: create, read, source assignment, candidate workflow updates, and file/image upload.
List jobs
Returns a paginated list of job records, newest first. Requires jobs:read.
Primary address is always included in attributes. active_candidate_count and rejected_candidate_count are always returned as non-null integers; both are 0 when the job has no candidates. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). contacts is always returned as an array of job_contact:<sqid> tokens, primary contact first and empty when none. Use include for additional sideloads.
Parameters
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
sort_orderstringquerySort by created_at: asc or desc (default desc)
includestringqueryOptional includes: primary_location, source, notes, flow, company
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Jobs list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a job
Creates a job record. Requires jobs:write. Create can set custom fields in the same format as PATCH.
Body
namestringrequiredJob name
company_idstringrequiredcompany ID to associate the job with
created_bystringuser ID of the record creator
assigned_tostringuser ID to assign the job to
assigned_bystringuser ID of the assigner
workflow_idstringJob workflow ID to attach on creation
workflow_phase_idstringJob-workflow phase ID to place the new job in. Requires workflow_id (the job workflow). Must belong to that workflow. Defaults to the first phase when omitted. Does not apply to candidate_workflow_id.
candidate_workflow_idstringCandidate workflow ID to attach on creation
primary_document_idstringfile ID for the primary document
custom_fieldsobjectObject keyed by custom-field slug. Values may be strings, numbers, booleans, arrays, objects, or null. Image/file custom fields are read as image:<sqid> / file:<sqid> reference tokens and may be written with a linked object sqid or matching token.
Response
Job created
Invalid request body
Invalid API key
Insufficient scope
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/jobs' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}
response = requests.post('https://api.searchsoftware.nl/v4/records/jobs', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/jobs", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
});
let response = client.post("https://api.searchsoftware.nl/v4/records/jobs")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"company_id": "string",
"created_by": "string",
"assigned_to": "string",
"assigned_by": "string",
"workflow_id": "string",
"workflow_phase_id": "string",
"candidate_workflow_id": "string",
"primary_document_id": "string",
"custom_fields": {}
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get jobs by IDs
Fetches multiple job records by ID in one request. active_candidate_count and rejected_candidate_count are always returned as non-null integers; both are 0 when the job has no candidates. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). contacts is always returned as an array of job_contact:<sqid> tokens, primary contact first and empty when none. Requires jobs:read.
Send up to 100 IDs in ids. Only existing, visible records are returned; unknown IDs are silently omitted. Result order is not guaranteed to match request order; match results by their id.
Body
idsarrayrequiredArray of record IDs to fetch (max 100)
Parameters
includestringqueryOptional includes: source, notes, flow, company
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Get jobs by IDs results
Invalid id in request body
Invalid API key
Insufficient scope
Too many ids or invalid request body
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X POST 'https://api.searchsoftware.nl/v4/records/jobs/get-many' \
-H 'Content-Type: application/json' \
-d '{
"ids": []
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/get-many', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": []
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"ids": []
}
response = requests.post('https://api.searchsoftware.nl/v4/records/jobs/get-many', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/get-many')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"ids": []
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"ids": []
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/jobs/get-many", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/get-many');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"ids": []
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"ids": []
});
let response = client.post("https://api.searchsoftware.nl/v4/records/jobs/get-many")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"ids": []
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a job
Fetches one job by ID. active_candidate_count and rejected_candidate_count are always returned as non-null integers; both are 0 when the job has no candidates. workflow_phase_status, workflow_stage_status, and workflow_phase_status_changed_at are always returned as nullable attributes derived from the record's workflow flow. alias is always returned as an array of the record's stored alias strings (empty when none). contacts is always returned as an array of job_contact:<sqid> tokens, primary contact first and empty when none. Requires jobs:read.
Parameters
idstringrequiredpathJob ID
includestringqueryOptional includes: primary_location, source, notes, flow, company
valuesstringquerySet to true to add a per-item values object keyed by attributes fields. Values hydrate reference tokens and fixed reference ids. Separate from include/objects behavior.
Response
Job found
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update a job
Updates a record name and/or custom field values addressed by field slug. Requires jobs:write.
Send name, custom_fields, or both. custom_fields keys must match the field slug exposed on reads; JSON null clears a value.
Body
namestringNew record name. For jobs this updates the title.
custom_fieldsobjectCustom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.
Parameters
idstringrequiredpathJob ID
Response
Record updated
Invalid id or request body
Invalid API key
Insufficient scope
Record not found
No changes, invalid name, unknown field, or validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/records/jobs/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "Jane Doe",
"custom_fields": {}
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Jane Doe",
"custom_fields": {}
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "Jane Doe",
"custom_fields": {}
}
response = requests.patch('https://api.searchsoftware.nl/v4/records/jobs/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "Jane Doe",
"custom_fields": {}
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "Jane Doe",
"custom_fields": {}
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/records/jobs/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "Jane Doe",
"custom_fields": {}
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "Jane Doe",
"custom_fields": {}
});
let response = client.patch("https://api.searchsoftware.nl/v4/records/jobs/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "Jane Doe",
"custom_fields": {}
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set job source
Assigns a source to a job. Requires jobs:write.
Body
source_idstringrequiredSource ID
Parameters
idstringrequiredpathJob ID
Response
Source set
Invalid id or body
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X PUT 'https://api.searchsoftware.nl/v4/records/jobs/{id}/source' \
-H 'Content-Type: application/json' \
-d '{
"source_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/source', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"source_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"source_id": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/records/jobs/{id}/source', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/source')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"source_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"source_id": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/records/jobs/{id}/source", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/source');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"source_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"source_id": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/records/jobs/{id}/source")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"source_id": "string"
}{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"source_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set job workflow phase
Sets a workflow phase on a job. Requires jobs:write.
Body
workflow_idstringrequiredWorkflow ID
phase_status_idstringrequiredPhase status ID
notestringOptional note
Parameters
idstringrequiredpathJob ID
Response
Workflow phase set
Invalid id or body
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X PUT 'https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase' \
-H 'Content-Type: application/json' \
-d '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"workflow_id": "vM7Lp2q",
"phase_status_id": "vM7Lp2q",
"log_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set candidate workflow phase
Sets a workflow phase on a candidate within a job. Requires jobs:write.
Body
workflow_idstringrequiredWorkflow ID
phase_status_idstringrequiredPhase status ID
notestringOptional note
Parameters
idstringrequiredpathJob ID
person_idstringrequiredpathPerson ID
Response
Workflow phase set
Invalid id or body
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X PUT 'https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase' \
-H 'Content-Type: application/json' \
-d '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"workflow_id": "string",
"phase_status_id": "string",
"note": "string"
}{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"workflow_id": "vM7Lp2q",
"phase_status_id": "vM7Lp2q",
"log_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List aliases for a job
Returns all aliases attached to the job. Requires jobs:read.
Parameters
idstringrequiredpathJob ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Alias list
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add an alias to a job
Creates a new alias for the job. Duplicate aliases for the same job are rejected (case-insensitive). Requires jobs:write.
Body
aliasstringrequiredAlias text
Parameters
idstringrequiredpathJob ID
Response
Alias created
Invalid id or body
Invalid API key
Insufficient scope
Job not found
Validation failed or duplicate alias
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases' \
-H 'Content-Type: application/json' \
-d '{
"alias": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"alias": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"alias": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"alias": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"alias": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"alias": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"alias": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"alias": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete an alias from a job
Removes an alias from the job. Requires jobs:write.
Parameters
idstringrequiredpathJob ID
alias_idstringrequiredpathAlias ID
Response
Alias deleted
Invalid id
Invalid API key
Insufficient scope
Job or alias not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"alias_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List bookmarks for a job
Returns all bookmarks linked to the job. Requires jobs:read.
Parameters
idstringrequiredpathJob ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Bookmark list
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add a bookmark to a job
Creates a new bookmark linked to the job. Requires jobs:write.
Body
urlstringrequiredBookmark URL
titlestringBookmark title
commentstringOptional comment
Parameters
idstringrequiredpathJob ID
Response
Bookmark created
Invalid id or body
Invalid API key
Insufficient scope
Job not found
Validation failed
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks' \
-H 'Content-Type: application/json' \
-d '{
"url": "string",
"title": "string",
"comment": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "string",
"title": "string",
"comment": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"url": "string",
"title": "string",
"comment": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"url": "string",
"title": "string",
"comment": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"url": "string",
"title": "string",
"comment": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"url": "string",
"title": "string",
"comment": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"url": "string",
"title": "string",
"comment": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"url": "string",
"title": "string",
"comment": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete a bookmark from a job
Removes a bookmark from the job. Requires jobs:write.
Parameters
idstringrequiredpathJob ID
bookmark_idstringrequiredpathBookmark ID
Response
Bookmark deleted
Invalid id
Invalid API key
Insufficient scope
Job or bookmark not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"bookmark_id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List files for a job
Lists files attached to a job. Requires jobs:read.
Parameters
idstringrequiredpathJob ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Files list
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/files'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/files', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/files')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/files')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/files", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/files');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/files")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "file",
"attributes": {
"name": "CV John Doe",
"filename": "abc123_cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List images for a job
Lists images attached to a job. Requires jobs:read.
Parameters
idstringrequiredpathJob ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Images list
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/images'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/images', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/images')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/images')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/images", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/images');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/images")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "image",
"attributes": {
"name": "Headshot",
"filename": "abc123_headshot.jpg",
"mime": "image/jpeg",
"size": 204800,
"width": 400,
"height": 400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List communications for a job
Lists communications attached to a job. Requires jobs:read.
Parameters
idstringrequiredpathJob ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
includestringqueryOptional includes: method
Response
Communications list
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/communications'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/communications', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/communications')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/communications')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/communications", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/communications');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/communications")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Upload a file to a job
Uploads a file to a job using multipart/form-data. Include file as binary data and optional primary_document ("true" or "false") to set primary_document_id.
Body
filestring<binary>requiredFile binary data
primary_documentstringSet to "true" to update primary document
Parameters
idstringrequiredpathJob ID
Response
File uploaded
Invalid id or no file provided
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload' \
-H 'Content-Type: multipart/form-data' \
-d '{
"file": "<binary>",
"primary_document": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"primary_document": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"file": "<binary>",
"primary_document": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'
request.body = '{
"file": "<binary>",
"primary_document": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"file": "<binary>",
"primary_document": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"file": "<binary>",
"primary_document": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"file": "<binary>",
"primary_document": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"file": "<binary>",
"primary_document": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Upload an image to a job
Uploads an image to a job using multipart/form-data. Include file as binary data and optional profile_picture ("true" or "false") to set image_id.
Body
filestring<binary>requiredImage binary data
profile_picturestringSet to "true" to update profile picture
Parameters
idstringrequiredpathJob ID
Response
Image uploaded
Invalid id or no file provided
Invalid API key
Insufficient scope
Record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload' \
-H 'Content-Type: multipart/form-data' \
-d '{
"file": "<binary>",
"profile_picture": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"profile_picture": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"file": "<binary>",
"profile_picture": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'
request.body = '{
"file": "<binary>",
"profile_picture": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"file": "<binary>",
"profile_picture": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"file": "<binary>",
"profile_picture": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"file": "<binary>",
"profile_picture": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"file": "<binary>",
"profile_picture": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "headshot.jpg",
"mime": "image/jpeg",
"size": 204800
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Files
Stored files attached to records, comments, and emails: download the bytes.
Download a file
Streams the stored bytes of one file. id is the file id returned by GET /v4/records/{type}/{id}/files or in an email's attachments array.
Requires both files:read and the read scope of the record the file is attached to (people:read, companies:read, jobs:read, comments:read, emails:read, or <plural_slug>:read for a custom record). A key holding only one of the two receives 403.
The response carries the file's own Content-Type and Content-Disposition: attachment; filename="...". Pass disposition=inline to render in a browser instead of downloading. The response is not cacheable.
Parameters
idstringrequiredpathFile ID
dispositionstringqueryattachment (default) or inline
Response
File bytes
Invalid id
Invalid API key
Insufficient scope
File not found, unlinked, or with no stored content
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: files:read
apikey_authapiKey in queryAPI key in query string
Scopes: files:read
curl -X GET 'https://api.searchsoftware.nl/v4/files/{id}/download'const response = await fetch('https://api.searchsoftware.nl/v4/files/{id}/download', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/files/{id}/download')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/files/{id}/download')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/files/{id}/download", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/files/{id}/download');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/files/{id}/download")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}"<binary>"{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Job Contacts
Contacts linked to a job: list, add, and update.
List contacts for a job
Returns contacts linked to a job, ordered by primary first then oldest first. Requires jobs:read.
Use include=person to sideload basic person data (name, image_url) on each contact.
Parameters
idstringrequiredpathJob ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
includestringqueryOptional includes: person
Response
Job contacts list
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job_contact",
"attributes": {
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string"
}
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add contact to job
Links a person to a job as a contact. Idempotent - re-posting the same person returns the existing record unchanged. If is_primary is true, the person becomes the exclusive primary contact (any previous primary is unset). Requires jobs:write.
Body
person_idstringrequiredPerson ID to add as contact
is_primarybooleanSet this person as the primary contact (default false)
notestringOptional note for this contact relationship
Parameters
idstringrequiredpathJob ID
Response
Contact added or already exists
Invalid id or body
Invalid API key
Insufficient scope
Job or person not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X POST 'https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts' \
-H 'Content-Type: application/json' \
-d '{
"person_id": "string",
"is_primary": true,
"note": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"person_id": "string",
"is_primary": true,
"note": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"person_id": "string",
"is_primary": True,
"note": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"person_id": "string",
"is_primary": true,
"note": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"person_id": "string",
"is_primary": true,
"note": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"person_id": "string",
"is_primary": true,
"note": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"person_id": "string",
"is_primary": true,
"note": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"person_id": "string",
"is_primary": true,
"note": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"job_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update job contact
Updates is_primary and/or note on an existing job contact record. Both fields are optional - only supplied fields are applied. If is_primary is true, this contact becomes the exclusive primary (any previous primary is unset). Requires jobs:write.
Body
is_primarybooleanPromote or demote this contact as primary (omit to leave unchanged)
notestringUpdate the note for this contact relationship (omit to leave unchanged)
Parameters
idstringrequiredpathJob ID
contact_idstringrequiredpathJob contact record ID
Response
Contact updated
Invalid id, contact_id, or body
Invalid API key
Insufficient scope
Job contact not found
Update failed
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:write
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}' \
-H 'Content-Type: application/json' \
-d '{
"is_primary": true,
"note": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"is_primary": true,
"note": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"is_primary": True,
"note": "string"
}
response = requests.patch('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"is_primary": true,
"note": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"is_primary": true,
"note": "string"
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"is_primary": true,
"note": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"is_primary": true,
"note": "string"
});
let response = client.patch("https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"is_primary": true,
"note": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"job_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string"
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Job Candidates
Candidates linked to a job: list and get.
List candidates for a job
Returns candidates linked to a job, ordered newest first. Requires jobs:read.
Use include=person to sideload basic person data (name, image_url, email_address) on each candidate.
Parameters
idstringrequiredpathJob ID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
includestringqueryOptional includes: person
Response
Job candidates list
Invalid id
Invalid API key
Insufficient scope
Job not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job_candidate",
"attributes": {
"person_id": "vM7Lp2q",
"status_id": "vM7Lp2q",
"ranking": 0,
"created_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"last_status_changed_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string",
"email_address": "string"
}
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a single job candidate
Returns a single candidate record for a job. Returns 404 if the candidate does not exist or does not belong to the specified job. Requires jobs:read.
Use include=person to sideload basic person data (name, image_url, email_address).
Parameters
idstringrequiredpathJob ID
candidate_idstringrequiredpathJob candidate record ID
includestringqueryOptional includes: person
Response
Job candidate
Invalid id or candidate_id
Invalid API key
Insufficient scope
Job or candidate not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: jobs:read
apikey_authapiKey in queryAPI key in query string
Scopes: jobs:read
curl -X GET 'https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}'const response = await fetch('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "job_candidate",
"attributes": {
"person_id": "vM7Lp2q",
"status_id": "vM7Lp2q",
"ranking": 0,
"created_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"last_status_changed_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string",
"email_address": "string"
}
}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Sources
Available source records.
List sources
Lists all available sources. Requires sources:read.
Response
Sources list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: sources:read
apikey_authapiKey in queryAPI key in query string
Scopes: sources:read
curl -X GET 'https://api.searchsoftware.nl/v4/sources'const response = await fetch('https://api.searchsoftware.nl/v4/sources', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/sources')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/sources')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/sources", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/sources');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/sources")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"parent_source_id": "vM7Lp2q",
"name": "LinkedIn",
"description": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Workflows
Available workflow, phase, and stage records.
List workflows
Lists all workflow definitions in the workspace. Requires workflows:read.
Response
Workflows list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: workflows:read
apikey_authapiKey in queryAPI key in query string
Scopes: workflows:read
curl -X GET 'https://api.searchsoftware.nl/v4/workflows'const response = await fetch('https://api.searchsoftware.nl/v4/workflows', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/workflows')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/workflows')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/workflows", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/workflows');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/workflows")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "workflow",
"attributes": {
"name": "Hiring Pipeline",
"for_item_type": "job_candidate",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List workflow phases
Lists all available workflow phases. Requires workflows:read.
Response
Workflow phases list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: workflows:read
apikey_authapiKey in queryAPI key in query string
Scopes: workflows:read
curl -X GET 'https://api.searchsoftware.nl/v4/workflows/phases'const response = await fetch('https://api.searchsoftware.nl/v4/workflows/phases', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/workflows/phases')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/workflows/phases')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/workflows/phases", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/workflows/phases');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/workflows/phases")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "workflow-phase",
"attributes": {
"workflow_id": "vM7Lp2q",
"stage_id": "vM7Lp2q",
"status": "Active",
"order": 1,
"color": "#00FF00",
"hide_content": false,
"is_final": false,
"available_in_draft_list": true,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List workflow stages
Lists all available workflow stages. Requires workflows:read.
Response
Workflow stages list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: workflows:read
apikey_authapiKey in queryAPI key in query string
Scopes: workflows:read
curl -X GET 'https://api.searchsoftware.nl/v4/workflows/stages'const response = await fetch('https://api.searchsoftware.nl/v4/workflows/stages', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/workflows/stages')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/workflows/stages')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/workflows/stages", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/workflows/stages');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/workflows/stages")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "workflow-stage",
"attributes": {
"workflow_id": "vM7Lp2q",
"status": "Screening",
"order": 1,
"color": "#3B82F6",
"color_bg": "#EFF6FF",
"color_text": "#1E40AF",
"completion_expected_percentage": 25,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Users
Workspace user accounts.
List users
Lists all users in the workspace. Requires users:read.
Response
Users list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: users:read
apikey_authapiKey in queryAPI key in query string
Scopes: users:read
curl -X GET 'https://api.searchsoftware.nl/v4/users'const response = await fetch('https://api.searchsoftware.nl/v4/users', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/users')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/users')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/users", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/users');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/users")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "user",
"attributes": {
"name": "string",
"full_name": "string",
"email": "string",
"email_verified_at": "2026-03-10T14:30:00Z",
"phone": "string",
"active": true,
"image_id": "vM7Lp2q",
"image_url": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a user
Fetches one user by ID. Requires users:read.
Parameters
idstringrequiredpathUser ID
Response
User found
Invalid id
Invalid API key
Insufficient scope
User not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: users:read
apikey_authapiKey in queryAPI key in query string
Scopes: users:read
curl -X GET 'https://api.searchsoftware.nl/v4/users/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/users/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/users/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/users/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/users/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/users/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/users/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "user",
"attributes": {
"name": "string",
"full_name": "string",
"email": "string",
"email_verified_at": "2026-03-10T14:30:00Z",
"phone": "string",
"active": true,
"image_id": "vM7Lp2q",
"image_url": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Communications
Communication history records and available communication methods.
List communications
Returns a paginated list of communication records, newest first. Requires communications:read.
Filter to a specific record with owner_type + owner_id (both must be provided together).
Parameters
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
includestringqueryOptional includes: method
owner_typestringqueryOwner record type: person, company, job, or job_contact
owner_idstringqueryOwner record ID (required when owner_type is set)
Response
Communications list
Invalid owner_id or mismatched owner_type/owner_id
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: communications:read
apikey_authapiKey in queryAPI key in query string
Scopes: communications:read
curl -X GET 'https://api.searchsoftware.nl/v4/communications'const response = await fetch('https://api.searchsoftware.nl/v4/communications', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/communications')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/communications')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/communications", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/communications');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/communications")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a communication
Creates a communication record and links it to an owner record. Requires communications:write.
Body
subjectstringrequiredSubject
summarystringrequiredSummary or body text
method_idstringrequiredCommunication method ID
datestringrequiredThe day the communication took place (YYYY-MM-DD). A datetime is still accepted for backward compatibility; its time component is discarded.
owner_typestringrequiredOwner record type: person, company, job, or job_contact
owner_idstringrequiredOwner record ID
created_bystringUser ID of the record creator
Response
Communication created
Invalid request body
Invalid API key
Insufficient scope
Owner record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: communications:write
apikey_authapiKey in queryAPI key in query string
Scopes: communications:write
curl -X POST 'https://api.searchsoftware.nl/v4/communications' \
-H 'Content-Type: application/json' \
-d '{
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/communications', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/communications', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/communications')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/communications", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/communications');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/communications")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"subject": "string",
"summary": "string",
"method_id": "string",
"date": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List communication methods
Returns all available communication methods, sorted alphabetically. Requires communications:read.
Response
Communication methods list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: communications:read
apikey_authapiKey in queryAPI key in query string
Scopes: communications:read
curl -X GET 'https://api.searchsoftware.nl/v4/communication-methods'const response = await fetch('https://api.searchsoftware.nl/v4/communication-methods', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/communication-methods')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/communication-methods')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/communication-methods", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/communication-methods');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/communication-methods")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "communication_method",
"attributes": {
"name": "Phone"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a communication method
Creates a new communication method. Requires communications:write.
Body
namestringrequiredMethod name (e.g. Phone, Email, LinkedIn)
Response
Communication method created
Invalid request body
Invalid API key
Insufficient scope
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: communications:write
apikey_authapiKey in queryAPI key in query string
Scopes: communications:write
curl -X POST 'https://api.searchsoftware.nl/v4/communication-methods' \
-H 'Content-Type: application/json' \
-d '{
"name": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/communication-methods', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/communication-methods', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/communication-methods')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/communication-methods", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/communication-methods');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/communication-methods")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "communication_method",
"attributes": {
"name": "Phone"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Comments
Comment records attached to people, companies, jobs, or job contacts.
List comments for todos
Returns every comment and image attached to each requested todo, oldest first. Requires both todos:read and comments:read.
Body
idsarrayrequiredTodo IDs to fetch comments for (max 100)
Response
Comments grouped by todo ID
Invalid todo ID or request body
Invalid API key
Insufficient scope
Too many todo IDs
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: comments:read
apikey_authapiKey in queryAPI key in query string
Scopes: comments:read
curl -X POST 'https://api.searchsoftware.nl/v4/comments/for-todos' \
-H 'Content-Type: application/json' \
-d '{
"ids": []
}'const response = await fetch('https://api.searchsoftware.nl/v4/comments/for-todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": []
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"ids": []
}
response = requests.post('https://api.searchsoftware.nl/v4/comments/for-todos', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/comments/for-todos')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"ids": []
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"ids": []
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/comments/for-todos", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/comments/for-todos');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"ids": []
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"ids": []
});
let response = client.post("https://api.searchsoftware.nl/v4/comments/for-todos")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"ids": []
}{
"status": "ok",
"data": {}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List comments
Returns a paginated list of comment records, newest first. Requires comments:read.
Filter to a specific record with owner_type + owner_id (both must be provided together).
Parameters
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
owner_typestringqueryOwner record type: person, company, job, or job_contact
owner_idstringqueryOwner record ID (required when owner_type is set)
Response
Comments list
Invalid owner_id or mismatched owner_type/owner_id
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: comments:read
apikey_authapiKey in queryAPI key in query string
Scopes: comments:read
curl -X GET 'https://api.searchsoftware.nl/v4/comments'const response = await fetch('https://api.searchsoftware.nl/v4/comments', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/comments')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/comments')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/comments", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/comments');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/comments")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "comment",
"attributes": {
"text": "Great candidate!",
"user_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a comment
Creates a comment and links it to an owner record. Requires comments:write.
Body
textstringrequiredComment body text
owner_typestringrequiredOwner record type: person, company, job, or job_contact
owner_idstringrequiredOwner record ID
user_idstringOptional user ID of the comment author
Response
Comment created
Invalid request body
Invalid API key
Insufficient scope
Owner record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: comments:write
apikey_authapiKey in queryAPI key in query string
Scopes: comments:write
curl -X POST 'https://api.searchsoftware.nl/v4/comments' \
-H 'Content-Type: application/json' \
-d '{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/comments', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/comments')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/comments", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/comments');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/comments")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"user_id": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "comment",
"attributes": {
"text": "Great candidate!",
"user_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Notes
Note records attached to people, companies, jobs, or job contacts.
List notes
Returns a paginated list of note records, newest first. Requires notes:read.
Filter to a specific record with owner_type + owner_id (both must be provided together).
Parameters
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
owner_typestringqueryOwner record type: person, company, job, or job_contact
owner_idstringqueryOwner record ID (required when owner_type is set)
Response
Notes list
Invalid owner_id or mismatched owner_type/owner_id
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: notes:read
apikey_authapiKey in queryAPI key in query string
Scopes: notes:read
curl -X GET 'https://api.searchsoftware.nl/v4/notes'const response = await fetch('https://api.searchsoftware.nl/v4/notes', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/notes')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/notes')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/notes", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/notes');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/notes")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "note",
"attributes": {
"title": "Interview notes",
"text": "Strong communication skills...",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a note
Creates a note and links it to an owner record. Requires notes:write.
Body
titlestringrequiredTitle
textstringrequiredNote body text
owner_typestringrequiredOwner record type: person, company, job, or job_contact
owner_idstringrequiredOwner record ID
created_bystringUser ID of the record creator
Response
Note created
Invalid request body
Invalid API key
Insufficient scope
Owner record not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: notes:write
apikey_authapiKey in queryAPI key in query string
Scopes: notes:write
curl -X POST 'https://api.searchsoftware.nl/v4/notes' \
-H 'Content-Type: application/json' \
-d '{
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/notes', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/notes', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/notes')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/notes", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/notes');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/notes")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"title": "string",
"text": "string",
"owner_type": "string",
"owner_id": "string",
"created_by": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "note",
"attributes": {
"title": "Interview notes",
"text": "Strong communication skills...",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Work History
Work history entries linking people to companies.
List work history entries
Returns a paginated list of work history entries. Filter by person_id or company_id. Requires work_history:read.
Parameters
person_idstringqueryFilter by person SqID
company_idstringqueryFilter by company SqID
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Work history list
Invalid filter param
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: work_history:read
apikey_authapiKey in queryAPI key in query string
Scopes: work_history:read
curl -X GET 'https://api.searchsoftware.nl/v4/work_history'const response = await fetch('https://api.searchsoftware.nl/v4/work_history', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/work_history')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/work_history')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/work_history", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/work_history');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/work_history")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "work_history",
"attributes": {
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a work history entry
Creates a new work history entry linking a person to a company. Requires work_history:write.
Body
person_idstringrequiredPerson ID
company_idstringCompany ID
company_namestringCompany name if no linked company
work_titlestringJob title
is_currentbooleanCurrent position flag
is_primary_contactbooleanPrimary contact flag
Response
Work history entry created
Invalid body
Invalid API key
Insufficient scope
Person or company not found
Validation failed
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: work_history:write
apikey_authapiKey in queryAPI key in query string
Scopes: work_history:write
curl -X POST 'https://api.searchsoftware.nl/v4/work_history' \
-H 'Content-Type: application/json' \
-d '{
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}'const response = await fetch('https://api.searchsoftware.nl/v4/work_history', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": True,
"is_primary_contact": True
}
response = requests.post('https://api.searchsoftware.nl/v4/work_history', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/work_history')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/work_history", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/work_history');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
});
let response = client.post("https://api.searchsoftware.nl/v4/work_history")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"person_id": "string",
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "work_history",
"attributes": {
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a work history entry
Returns a single work history entry by ID. Requires work_history:read.
Parameters
idstringrequiredpathWork history entry ID
Response
Work history entry
Invalid id
Invalid API key
Insufficient scope
Entry not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: work_history:read
apikey_authapiKey in queryAPI key in query string
Scopes: work_history:read
curl -X GET 'https://api.searchsoftware.nl/v4/work_history/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/work_history/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/work_history/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/work_history/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/work_history/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/work_history/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/work_history/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "work_history",
"attributes": {
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete a work history entry
Permanently deletes a work history entry. Requires work_history:write.
Parameters
idstringrequiredpathWork history entry ID
Response
Work history entry deleted
Invalid id
Invalid API key
Insufficient scope
Entry not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: work_history:write
apikey_authapiKey in queryAPI key in query string
Scopes: work_history:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/work_history/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/work_history/{id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/work_history/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/work_history/{id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/work_history/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/work_history/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/work_history/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"deleted": true,
"id": "vM7Lp2q"
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update a work history entry
Partially updates a work history entry. All body fields are optional. Requires work_history:write.
Body
company_idstringCompany ID
company_namestringCompany name if no linked company
work_titlestringJob title
is_currentbooleanCurrent position flag
is_primary_contactbooleanPrimary contact flag
Parameters
idstringrequiredpathWork history entry ID
Response
Work history entry updated
Invalid id or body
Invalid API key
Insufficient scope
Entry or company not found
Validation failed
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: work_history:write
apikey_authapiKey in queryAPI key in query string
Scopes: work_history:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/work_history/{id}' \
-H 'Content-Type: application/json' \
-d '{
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}'const response = await fetch('https://api.searchsoftware.nl/v4/work_history/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": True,
"is_primary_contact": True
}
response = requests.patch('https://api.searchsoftware.nl/v4/work_history/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/work_history/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/work_history/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/work_history/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
});
let response = client.patch("https://api.searchsoftware.nl/v4/work_history/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"company_id": "string",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "work_history",
"attributes": {
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Categories
Category groups and categories: the taxonomy plus linking categories to records. Group and category creates are find-or-create by name (no duplicates).
List category groups
Returns a paginated list of category groups. Pass name to fetch the single group with that exact name (trimmed, case-insensitive) — useful for find-or-create. Requires categories:read.
Parameters
namestringqueryExact group name to match (trimmed, case-insensitive)
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Category groups list
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:read
apikey_authapiKey in queryAPI key in query string
Scopes: categories:read
curl -X GET 'https://api.searchsoftware.nl/v4/category-groups'const response = await fetch('https://api.searchsoftware.nl/v4/category-groups', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/category-groups')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/category-groups')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/category-groups", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/category-groups');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/category-groups")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "category_group",
"attributes": {
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a category group
Creates a category group. Find-or-create: if a group with the same name already exists (trimmed, case-insensitive) it is returned instead of creating a duplicate. Requires categories:write.
Body
namestringrequiredCategory group name
Response
Category group created or reused
Invalid request body
Invalid API key
Insufficient scope
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:write
apikey_authapiKey in queryAPI key in query string
Scopes: categories:write
curl -X POST 'https://api.searchsoftware.nl/v4/category-groups' \
-H 'Content-Type: application/json' \
-d '{
"name": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/category-groups', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/category-groups', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/category-groups')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/category-groups", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/category-groups');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/category-groups")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category_group",
"attributes": {
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a category group
Returns a single category group by ID. Requires categories:read.
Parameters
idstringrequiredpathCategory group ID
Response
Category group
Invalid id
Invalid API key
Insufficient scope
Category group not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:read
apikey_authapiKey in queryAPI key in query string
Scopes: categories:read
curl -X GET 'https://api.searchsoftware.nl/v4/category-groups/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/category-groups/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/category-groups/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/category-groups/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/category-groups/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/category-groups/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/category-groups/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category_group",
"attributes": {
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete a category group
Permanently deletes a category group. Requires categories:write.
Parameters
idstringrequiredpathCategory group ID
Response
Category group deleted
Invalid id
Invalid API key
Insufficient scope
Category group not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:write
apikey_authapiKey in queryAPI key in query string
Scopes: categories:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/category-groups/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/category-groups/{id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/category-groups/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/category-groups/{id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/category-groups/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/category-groups/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/category-groups/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": "string"
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update a category group
Renames a category group. Requires categories:write.
Body
namestringrequiredNew category group name
Parameters
idstringrequiredpathCategory group ID
Response
Category group updated
Invalid id or body
Invalid API key
Insufficient scope
Category group not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:write
apikey_authapiKey in queryAPI key in query string
Scopes: categories:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/category-groups/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/category-groups/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string"
}
response = requests.patch('https://api.searchsoftware.nl/v4/category-groups/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/category-groups/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string"
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/category-groups/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/category-groups/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string"
});
let response = client.patch("https://api.searchsoftware.nl/v4/category-groups/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category_group",
"attributes": {
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List categories
Returns a paginated list of categories. Pass group_id to scope to one group and name to match an exact category name (trimmed, case-insensitive) — combine both for find-or-create within a group. Requires categories:read.
Parameters
group_idstringqueryFilter to a single category group by SqID
namestringqueryExact category name to match (trimmed, case-insensitive)
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
Response
Categories list
Invalid group_id
Invalid API key
Insufficient scope
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:read
apikey_authapiKey in queryAPI key in query string
Scopes: categories:read
curl -X GET 'https://api.searchsoftware.nl/v4/categories'const response = await fetch('https://api.searchsoftware.nl/v4/categories', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/categories')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/categories')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/categories", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/categories');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/categories")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create a category
Creates a category within a group. Find-or-create: if a category with the same name already exists in that group (trimmed, case-insensitive) it is returned instead of creating a duplicate. Requires categories:write.
Body
namestringrequiredCategory name
group_idstringrequiredOwning category group ID
Response
Category created or reused
Invalid request body
Invalid API key
Insufficient scope
Category group not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:write
apikey_authapiKey in queryAPI key in query string
Scopes: categories:write
curl -X POST 'https://api.searchsoftware.nl/v4/categories' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"group_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/categories', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"group_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"group_id": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/categories', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/categories')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"group_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"group_id": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/categories", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/categories');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"group_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"group_id": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/categories")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"group_id": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get a category
Returns a single category by ID. Requires categories:read.
Parameters
idstringrequiredpathCategory ID
Response
Category
Invalid id
Invalid API key
Insufficient scope
Category not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:read
apikey_authapiKey in queryAPI key in query string
Scopes: categories:read
curl -X GET 'https://api.searchsoftware.nl/v4/categories/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/categories/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/categories/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/categories/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/categories/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/categories/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/categories/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete a category
Permanently deletes a category. Requires categories:write.
Parameters
idstringrequiredpathCategory ID
Response
Category deleted
Invalid id
Invalid API key
Insufficient scope
Category not found
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:write
apikey_authapiKey in queryAPI key in query string
Scopes: categories:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/categories/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/categories/{id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/categories/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/categories/{id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/categories/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/categories/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/categories/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": "string"
}{
"status": "error",
"error": {
"code": "INVALID_ID",
"status_code": 400,
"message": "Invalid id"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update a category
Renames a category. Requires categories:write.
Body
namestringrequiredNew category name
Parameters
idstringrequiredpathCategory ID
Response
Category updated
Invalid id or body
Invalid API key
Insufficient scope
Category not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: categories:write
apikey_authapiKey in queryAPI key in query string
Scopes: categories:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/categories/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/categories/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string"
}
response = requests.patch('https://api.searchsoftware.nl/v4/categories/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/categories/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string"
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/categories/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/categories/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string"
});
let response = client.patch("https://api.searchsoftware.nl/v4/categories/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Todos
Todo records: list, search, create, update, assignment, ownership, completion, and board-list movement.
List todos
List todos. Requires todos:read.
Parameters
limitstringqueryMax results, 1-100, default 25
offsetstringqueryZero-based offset, default 0
owner_typestringqueryOwner type: person, company, job, or custom:
owner_idstringqueryOwner ID
assigned_tostringqueryAssigned user ID
list_idstringqueryBoard list ID
statusstringqueryopen, completed, or all
Response
List todos
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos'const response = await fetch('https://api.searchsoftware.nl/v4/todos', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create todo
Create todo. Requires todos:write.
Body
textstringrequiredowner_typestringowner_idstringassigned_tostringcreated_bystringlist_idstringlabel_idsarrayis_priority_taskbooleandue_atstringResponse
Create todo
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos' \
-H 'Content-Type: application/json' \
-d '{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": true,
"due_at": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": true,
"due_at": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": True,
"due_at": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": true,
"due_at": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": true,
"due_at": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": true,
"due_at": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": true,
"due_at": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"text": "string",
"owner_type": "string",
"owner_id": "string",
"assigned_to": "string",
"created_by": "string",
"list_id": "string",
"label_ids": [],
"is_priority_task": true,
"due_at": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get todos by IDs
Fetch multiple todos in one request. Requires todos:read.
Send up to 100 IDs in ids. Only existing todos are returned; unknown IDs are silently omitted. Result order is not guaranteed to match request order; match results by their id.
Body
idsarrayrequiredArray of todo IDs to fetch (max 100)
Response
Todos
Invalid id in request body
Invalid API key
Insufficient scope
Too many ids or invalid request body
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X POST 'https://api.searchsoftware.nl/v4/todos/get-many' \
-H 'Content-Type: application/json' \
-d '{
"ids": []
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/get-many', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": []
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"ids": []
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/get-many', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/get-many')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"ids": []
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"ids": []
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/get-many", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/get-many');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"ids": []
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"ids": []
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/get-many")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"ids": []
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Search todos
Searches todos in the todos index. Requires todos:read.
All request fields are optional. Blank or omitted query defaults to match-all; omitted limit defaults to 10 and is clamped to 1-200; negative offset clamps to 0; omitted sort defaults to created_at desc. Filter clauses address bare todo metadata keys such as owner_type, assigned_to, list_id, completed_at, and is_priority_task. checklist is an array of task objects mirroring TodoResponse and is not addressable as a scalar; its leaf paths checklist.text, checklist.completed, and checklist.id are addressable. Do not prefix fields with meta..
Body
querystringSearch query. Blank or omitted values default to match-all.
limitinteger<int32>Maximum results. Defaults to 10 and is clamped to 1-200.
offsetinteger<int32>Zero-based offset. Defaults to 0 and negative values clamp to 0.
filtersArray<object>Additional filter groups.
sortArray<object>Sort fields. Empty or omitted values default to created_at desc.
Response
Todo search results
Invalid request body
Invalid API key
Insufficient scope
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X POST 'https://api.searchsoftware.nl/v4/todos/search' \
-H 'Content-Type: application/json' \
-d '{
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/search', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/search')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/search", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/search');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/search")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}{
"status": "ok",
"data": {
"count": 1,
"results": [
{
"id": "encoded-todo-sqid",
"score": 0.75,
"attributes": {}
}
]
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get todo
Get todo. Requires todos:read.
Parameters
idstringrequiredpathTodo ID
Response
Get todo
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete todo
Delete todo. Requires todos:write.
Parameters
idstringrequiredpathTodo ID
Response
Delete todo
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/todos/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/todos/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/todos/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/todos/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": "string"
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update todo
Update todo. Requires todos:write.
Body
textstringis_priority_taskbooleandue_atstringRFC3339 datetime or null to clear
Parameters
idstringrequiredpathTodo ID
Response
Update todo
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/todos/{id}' \
-H 'Content-Type: application/json' \
-d '{
"text": "string",
"is_priority_task": true,
"due_at": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"text": "string",
"is_priority_task": true,
"due_at": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"text": "string",
"is_priority_task": True,
"due_at": "string"
}
response = requests.patch('https://api.searchsoftware.nl/v4/todos/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"text": "string",
"is_priority_task": true,
"due_at": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"text": "string",
"is_priority_task": true,
"due_at": "string"
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/todos/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"text": "string",
"is_priority_task": true,
"due_at": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"text": "string",
"is_priority_task": true,
"due_at": "string"
});
let response = client.patch("https://api.searchsoftware.nl/v4/todos/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"text": "string",
"is_priority_task": true,
"due_at": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Complete todo
Complete todo. Requires todos:write.
Body
completed_bystringParameters
idstringrequiredpathTodo ID
Response
Complete todo
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/{id}/complete' \
-H 'Content-Type: application/json' \
-d '{
"completed_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"completed_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"completed_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/{id}/complete', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/complete')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"completed_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"completed_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/{id}/complete", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/complete');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"completed_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"completed_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/{id}/complete")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"completed_by": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Reopen todo
Reopen todo. Requires todos:write.
Parameters
idstringrequiredpathTodo ID
Response
Reopen todo
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/{id}/reopen'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/reopen', {
method: 'POST',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.post('https://api.searchsoftware.nl/v4/todos/{id}/reopen')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/reopen')
request = Net::HTTP::Post.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/{id}/reopen", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/reopen');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.post("https://api.searchsoftware.nl/v4/todos/{id}/reopen")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Assign or unassign todo user
Assign or unassign todo user. Requires todos:write.
Body
user_idstringParameters
idstringrequiredpathTodo ID
Response
Assign or unassign todo user
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PUT 'https://api.searchsoftware.nl/v4/todos/{id}/assignee' \
-H 'Content-Type: application/json' \
-d '{
"user_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/assignee', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"user_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"user_id": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/todos/{id}/assignee', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/assignee')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"user_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"user_id": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/todos/{id}/assignee", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/assignee');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"user_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"user_id": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/todos/{id}/assignee")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"user_id": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Assign todo owner
Assign todo owner. Requires todos:write.
Body
owner_typestringrequiredowner_idstringrequiredParameters
idstringrequiredpathTodo ID
Response
Assign todo owner
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PUT 'https://api.searchsoftware.nl/v4/todos/{id}/owner' \
-H 'Content-Type: application/json' \
-d '{
"owner_type": "string",
"owner_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/owner', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"owner_type": "string",
"owner_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"owner_type": "string",
"owner_id": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/todos/{id}/owner', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/owner')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"owner_type": "string",
"owner_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"owner_type": "string",
"owner_id": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/todos/{id}/owner", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/owner');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"owner_type": "string",
"owner_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"owner_type": "string",
"owner_id": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/todos/{id}/owner")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"owner_type": "string",
"owner_id": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Move todo to board list
Move todo to board list. Requires todos:write.
Body
list_idstringParameters
idstringrequiredpathTodo ID
Response
Move todo to board list
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PUT 'https://api.searchsoftware.nl/v4/todos/{id}/list' \
-H 'Content-Type: application/json' \
-d '{
"list_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/list', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"list_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"list_id": "string"
}
response = requests.put('https://api.searchsoftware.nl/v4/todos/{id}/list', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/list')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"list_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"list_id": "string"
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/todos/{id}/list", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/list');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"list_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"list_id": "string"
});
let response = client.put("https://api.searchsoftware.nl/v4/todos/{id}/list")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"list_id": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Todo Boards
Todo boards: list, create, read, update, and delete.
List todo boards
List todo boards. Requires todos:read.
Parameters
limitstringqueryoffsetstringqueryResponse
List todo boards
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/boards'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/boards')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/boards", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/boards")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create todo board
Create todo board. Requires todos:write.
Body
namestringrequiredcreated_bystringResponse
Create todo board
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/boards' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"created_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"created_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"created_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/boards', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"created_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"created_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/boards", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"created_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"created_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/boards")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"created_by": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get todo board
Get todo board. Requires todos:read.
Parameters
idstringrequiredpathTodo board ID
Response
Get todo board
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/boards/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/boards/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/boards/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/boards/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete todo board
Delete todo board. Requires todos:write.
Parameters
idstringrequiredpathTodo board ID
Response
Delete todo board
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/todos/boards/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/{id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/todos/boards/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/{id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/todos/boards/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/todos/boards/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": "string"
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update todo board
Update todo board. Requires todos:write.
Body
namestringParameters
idstringrequiredpathTodo board ID
Response
Update todo board
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/todos/boards/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string"
}
response = requests.patch('https://api.searchsoftware.nl/v4/todos/boards/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string"
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/todos/boards/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string"
});
let response = client.patch("https://api.searchsoftware.nl/v4/todos/boards/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Todo Board Lists
Todo board lists: board-scoped listing and create, plus read, update, and delete.
List todo board lists
List todo board lists. Requires todos:read.
Parameters
idstringrequiredpathTodo board ID
Response
List todo board lists
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/boards/{id}/lists'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/boards/{id}/lists", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/boards/{id}/lists")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_board_list",
"attributes": {
"board_id": "vM7Lp2q",
"name": "Doing",
"text_color": "#ffffff",
"background_color": "#0f766e",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create todo board list
Create todo board list. Requires todos:write.
Body
namestringrequiredtext_colorstringbackground_colorstringcreated_bystringParameters
idstringrequiredpathTodo board ID
Response
Create todo board list
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/boards/{id}/lists' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/boards/{id}/lists", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/{id}/lists');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/boards/{id}/lists")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get todo board list
Get todo board list. Requires todos:read.
Parameters
idstringrequiredpathTodo board list ID
Response
Get todo board list
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/boards/lists/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/boards/lists/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/boards/lists/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete todo board list
Delete todo board list. Requires todos:write.
Parameters
idstringrequiredpathTodo board list ID
Response
Delete todo board list
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/todos/boards/lists/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/todos/boards/lists/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/todos/boards/lists/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": "string"
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update todo board list
Update todo board list. Requires todos:write.
Body
namestringtext_colorstringbackground_colorstringParameters
idstringrequiredpathTodo board list ID
Response
Update todo board list
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/todos/boards/lists/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"text_color": "string",
"background_color": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"text_color": "string",
"background_color": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"text_color": "string",
"background_color": "string"
}
response = requests.patch('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"text_color": "string",
"background_color": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"text_color": "string",
"background_color": "string"
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/todos/boards/lists/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/boards/lists/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"text_color": "string",
"background_color": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"text_color": "string",
"background_color": "string"
});
let response = client.patch("https://api.searchsoftware.nl/v4/todos/boards/lists/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"text_color": "string",
"background_color": "string"
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Todo Labels
Todo labels and labels linked to todos.
List todo labels
List todo labels. Requires todos:read.
Parameters
namestringquerylimitstringqueryoffsetstringqueryResponse
List todo labels
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/labels'const response = await fetch('https://api.searchsoftware.nl/v4/todos/labels', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/labels')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/labels')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/labels", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/labels');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/labels")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Create todo label
Create todo label. Requires todos:write.
Body
namestringrequiredtext_colorstringbackground_colorstringcreated_bystringResponse
Create todo label
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/labels' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/labels', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/labels', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/labels')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/labels", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/labels');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/labels")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Get todo label
Get todo label. Requires todos:read.
Parameters
idstringrequiredpathTodo label ID
Response
Get todo label
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/labels/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/labels/{id}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/labels/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/labels/{id}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/labels/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/labels/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/labels/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Delete todo label
Delete todo label. Requires todos:write.
Parameters
idstringrequiredpathTodo label ID
Response
Delete todo label
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/todos/labels/{id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/labels/{id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/todos/labels/{id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/labels/{id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/todos/labels/{id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/labels/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/todos/labels/{id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": "string"
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Update todo label
Update todo label. Requires todos:write.
Body
namestringtext_colorstringbackground_colorstringParameters
idstringrequiredpathTodo label ID
Response
Update todo label
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PATCH 'https://api.searchsoftware.nl/v4/todos/labels/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"text_color": "string",
"background_color": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/labels/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"text_color": "string",
"background_color": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "string",
"text_color": "string",
"background_color": "string"
}
response = requests.patch('https://api.searchsoftware.nl/v4/todos/labels/{id}', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/labels/{id}')
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "string",
"text_color": "string",
"background_color": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "string",
"text_color": "string",
"background_color": "string"
}`)
req, _ := http.NewRequest("PATCH", "https://api.searchsoftware.nl/v4/todos/labels/{id}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/labels/{id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"name": "string",
"text_color": "string",
"background_color": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "string",
"text_color": "string",
"background_color": "string"
});
let response = client.patch("https://api.searchsoftware.nl/v4/todos/labels/{id}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"text_color": "string",
"background_color": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}List labels for todo
List labels for todo. Requires todos:read.
Parameters
idstringrequiredpathTodo ID
Response
List labels for todo
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:read
apikey_authapiKey in queryAPI key in query string
Scopes: todos:read
curl -X GET 'https://api.searchsoftware.nl/v4/todos/{id}/labels'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/labels', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://api.searchsoftware.nl/v4/todos/{id}/labels')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/labels')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.searchsoftware.nl/v4/todos/{id}/labels", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/labels');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://api.searchsoftware.nl/v4/todos/{id}/labels")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Add todo label
Add todo label. Requires todos:write.
Body
label_idstringrequiredParameters
idstringrequiredpathTodo ID
Response
Add todo label
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/{id}/labels' \
-H 'Content-Type: application/json' \
-d '{
"label_id": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/labels', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"label_id": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"label_id": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/{id}/labels', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/labels')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"label_id": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"label_id": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/{id}/labels", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/labels');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"label_id": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"label_id": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/{id}/labels")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"label_id": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Set todo labels
Set todo labels. Requires todos:write.
Body
label_idsarrayrequiredParameters
idstringrequiredpathTodo ID
Response
Set todo labels
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X PUT 'https://api.searchsoftware.nl/v4/todos/{id}/labels' \
-H 'Content-Type: application/json' \
-d '{
"label_ids": []
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/labels', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"label_ids": []
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"label_ids": []
}
response = requests.put('https://api.searchsoftware.nl/v4/todos/{id}/labels', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/labels')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"label_ids": []
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"label_ids": []
}`)
req, _ := http.NewRequest("PUT", "https://api.searchsoftware.nl/v4/todos/{id}/labels", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/labels');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"label_ids": []
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"label_ids": []
});
let response = client.put("https://api.searchsoftware.nl/v4/todos/{id}/labels")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"label_ids": []
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Remove todo label
Remove todo label. Requires todos:write.
Parameters
idstringrequiredpathTodo ID
label_idstringrequiredpathTodo label ID
Response
Remove todo label
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X DELETE 'https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": "string"
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Todo Checklists
Checklist tasks attached to todos.
Create a todo checklist task
Create a todo checklist task. Requires todos:write.
Body
textstringrequiredcreated_bystringParameters
idstringrequiredpathTodo ID
Response
Create a todo checklist task
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/{id}/checklist' \
-H 'Content-Type: application/json' \
-d '{
"text": "string",
"created_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/checklist', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"text": "string",
"created_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"text": "string",
"created_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/{id}/checklist', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/checklist')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"text": "string",
"created_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"text": "string",
"created_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/{id}/checklist", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/checklist');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"text": "string",
"created_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"text": "string",
"created_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/{id}/checklist")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"text": "string",
"created_by": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Complete a todo checklist task
Complete a todo checklist task. Requires todos:write.
Body
completed_bystringParameters
idstringrequiredpathTodo ID
task_idstringrequiredpathChecklist task ID
Response
Complete a todo checklist task
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete' \
-H 'Content-Type: application/json' \
-d '{
"completed_by": "string"
}'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"completed_by": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"completed_by": "string"
}
response = requests.post('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete', json=payload)
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"completed_by": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"completed_by": "string"
}`)
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
"completed_by": "string"
}');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"completed_by": "string"
});
let response = client.post("https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"completed_by": "string"
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Reopen a todo checklist task
Reopen a todo checklist task. Requires todos:write.
Parameters
idstringrequiredpathTodo ID
task_idstringrequiredpathChecklist task ID
Response
Reopen a todo checklist task
Invalid id or request body
Invalid API key
Insufficient scope
Resource not found
Validation error
Internal server error
Authorization
bearer_authhttp (bearer) in headerAPI key in Authorization header
Scopes: todos:write
apikey_authapiKey in queryAPI key in query string
Scopes: todos:write
curl -X POST 'https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen'const response = await fetch('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen', {
method: 'POST',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.post('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen')
data = response.json()require 'net/http'
require 'json'
uri = URI('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen')
request = Net::HTTP::Post.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}<?php
$ch = curl_init('https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.post("https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}{
"status": "error",
"error": {
"code": "INVALID_BODY",
"status_code": 400,
"message": "Invalid request body"
}
}{
"status": "error",
"error": {
"code": "INVALID_API_KEY",
"status_code": 401,
"message": "Invalid API key"
}
}{
"status": "error",
"error": {
"code": "FORBIDDEN",
"status_code": 403,
"message": "Insufficient scope"
}
}{
"status": "error",
"error": {
"code": "NOT_FOUND",
"status_code": 404,
"message": "Record not found"
}
}{
"status": "error",
"error": {
"code": "VALIDATION_FAILED",
"status_code": 422,
"message": "Validation failed"
}
}{
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"status_code": 500,
"message": "Internal server error"
}
}Models
PrimaryEmailIncludeAttributes
objectaddressstring<email>is_primarybooleancreated_atstring<date-time>updated_atstring<date-time>{
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}PrimaryEmailInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}PrimaryPhoneIncludeAttributes
objectnumberstringis_primarybooleancreated_atstring<date-time>updated_atstring<date-time>{
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}PrimaryPhoneInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}PrimaryLocationIncludeAttributes
objectformattedstringis_primarybooleancreated_atstring<date-time>updated_atstring<date-time>{
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}PrimaryLocationInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}SourceIncludeAttributes
objectnamestringurl_idstring | nullcreated_atstring<date-time>updated_atstring<date-time>{
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}SourceInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}FlowIncludeAttributes
objectWorkflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.
phase_status_idstring | nullIdentifier
created_bystring | nullIdentifier
last_status_changed_bystring | nullIdentifier
last_status_changed_atstring<date-time> | nullcreated_atstring<date-time> | nullupdated_atstring<date-time> | null{
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}PersonFlowInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredWorkflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.
{
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}CompanyFlowInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredWorkflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.
{
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}JobFlowInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredWorkflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.
{
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}CompanyIncludeAttributes
objectnamestringimage_urlstring<uri> | nullcreated_atstring<date-time> | nullupdated_atstring<date-time> | null{
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}CompanyInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}NoteAttributes
objecttitlestring | nulltextstring | nulltypestring | nullcreated_bystring | nullIdentifier
last_edited_bystring | nullIdentifier
created_atstring<date-time>updated_atstring<date-time>{
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}NoteInclude
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}CustomFieldFormats
objectText custom-field render formats keyed by field slug. Values are plain, markdown, or html.
[key: string]stringplainmarkdownhtml{}RecordValues
objectOptional per-item hydrated values keyed by attributes field. Present only when values=true is requested. Scalar reference attributes hydrate to one public object summary; array attributes hydrate to an array of summaries, including empty and one-member arrays.
[key: string]any{}UpdateRecordRequest
objectnamestringNew record name. For jobs this updates the title.
custom_fieldsobjectCustom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.
{
"name": "Jane Doe",
"custom_fields": {}
}PersonAttributes
objectBase person fields plus custom field values keyed by field slug. Scalar fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings.
namestringcreated_atstring<date-time>updated_atstring<date-time>email_addressstring<email> | nullphone_numberstring | nulladdressstring | nullcurrent_companystring | nullCurrent employer name derived from the current work-history entry.
current_positionstring | nullCurrent work title derived from the current work-history entry.
assigned_tostring | nullIdentifier
assigned_atstring<date-time> | nullassigned_bystring | nullIdentifier
created_bystring | nullIdentifier
image_idstring | nullIdentifier
primary_document_idstring | nullIdentifier
genderstring | nullbirthdatestring<date> | nullDate of birth as a calendar day (YYYY-MM-DD). Null when the person has no birthdate on file.
image_urlstring<uri> | nullprofile_urlstring<uri> | nullAbsolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.
statusstringstatus_changed_atstring<date-time> | nullrelevant_career_experience_start_atstring<date-time> | nullworkflow_idstring | nullIdentifier
workflow_phase_statusstring | nullName of the workflow phase the record is currently in. Null when the record is not in a workflow phase.
workflow_stage_statusstring | nullName of the workflow stage that owns the current phase. Null when the record is not in a workflow phase or the phase has no stage.
workflow_phase_status_changed_atstring<date-time> | nullWhen the record last entered its current workflow phase. Null when the phase has never been set.
typesArray<string>Prefixed identifiers of the types linked to this person. Empty array when none.
aliasArray<string>Alternative names stored for this record, oldest first. Empty array when none.
[key: string]string | Array<string>{
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
}PersonObjects
objectprimary_emailobject | nullprimary_phoneobject | nullprimary_locationobject | nullsourceobject | nullflowobject | nullnotesArray<object>Included notes array (newest-first, max 25). Empty array when no notes.
{
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
}PersonData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredBase person fields plus custom field values keyed by field slug. Scalar fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings.
objectsobjectrequiredvaluesobjectOptional per-item hydrated values keyed by attributes field. Present only when values=true is requested. Scalar reference attributes hydrate to one public object summary; array attributes hydrate to an array of summaries, including empty and one-member arrays.
custom_field_formatsobjectrequiredText custom-field render formats keyed by field slug. Values are plain, markdown, or html.
{
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}PersonCreateData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredBase person fields plus custom field values keyed by field slug. Scalar fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings.
custom_field_formatsobjectrequiredText custom-field render formats keyed by field slug. Values are plain, markdown, or html.
{
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}PersonResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}PeopleListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "person_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}PersonCreateResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "person",
"attributes": {
"name": "Jane Doe",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"current_company": "string",
"current_position": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"gender": "string",
"birthdate": "1985-04-12",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"relevant_career_experience_start_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"person_type:Xy3",
"person_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}
}CompanyAttributes
objectBase company fields plus custom field values keyed by field slug. Scalar custom fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings. The derived active_job_count attribute is an integer.
namestringcreated_atstring<date-time>updated_atstring<date-time>email_addressstring<email> | nullphone_numberstring | nulladdressstring | nullactive_job_countinteger<int32>Number of active jobs attached to this company. Active means the job's status is one of "" (unset), "normal", or "highlight"; closed, inactive, and deleted jobs are excluded. Always present; 0 when the company has no active jobs.
assigned_tostring | nullIdentifier
assigned_atstring<date-time> | nullassigned_bystring | nullIdentifier
created_bystring | nullIdentifier
image_idstring | nullIdentifier
primary_document_idstring | nullIdentifier
image_urlstring<uri> | nullprofile_urlstring<uri> | nullAbsolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.
statusstringstatus_changed_atstring<date-time> | nullworkflow_idstring | nullIdentifier
workflow_phase_statusstring | nullName of the workflow phase the record is currently in. Null when the record is not in a workflow phase.
workflow_stage_statusstring | nullName of the workflow stage that owns the current phase. Null when the record is not in a workflow phase or the phase has no stage.
workflow_phase_status_changed_atstring<date-time> | nullWhen the record last entered its current workflow phase. Null when the phase has never been set.
typesArray<string>Prefixed identifiers of the types linked to this company. Empty array when none.
aliasArray<string>Alternative names stored for this record, oldest first. Empty array when none.
[key: string]string | Array<string>{
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
}CompanyObjects
objectprimary_emailobject | nullprimary_phoneobject | nullprimary_locationobject | nullsourceobject | nullflowobject | nullnotesArray<object>Included notes array (newest-first, max 25). Empty array when no notes.
{
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
}CompanyData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredBase company fields plus custom field values keyed by field slug. Scalar custom fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings. The derived active_job_count attribute is an integer.
objectsobjectrequiredvaluesobjectOptional per-item hydrated values keyed by attributes field. Present only when values=true is requested. Scalar reference attributes hydrate to one public object summary; array attributes hydrate to an array of summaries, including empty and one-member arrays.
custom_field_formatsobjectrequiredText custom-field render formats keyed by field slug. Values are plain, markdown, or html.
{
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}CompanyCreateData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredBase company fields plus custom field values keyed by field slug. Scalar custom fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings. The derived active_job_count attribute is an integer.
custom_field_formatsobjectrequiredText custom-field render formats keyed by field slug. Values are plain, markdown, or html.
{
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}CompanyResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}CompaniesListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_email": {
"id": "vM7Lp2q",
"type": "email_address",
"attributes": {
"address": "jane@example.com",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_phone": {
"id": "vM7Lp2q",
"type": "phone_number",
"attributes": {
"number": "+31612345678",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "company_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}CompanyCreateResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme Corp",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"email_address": "user@example.com",
"phone_number": "string",
"address": "string",
"active_job_count": 7,
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"company_type:Xy3",
"company_type:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}
}JobAttributes
objectBase job fields plus custom field values keyed by field slug. Scalar custom fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings. The derived active_candidate_count and rejected_candidate_count attributes are integers.
namestringcompany_idstring | nullIdentifier
created_atstring<date-time>updated_atstring<date-time>addressstring | nullassigned_tostring | nullIdentifier
assigned_atstring<date-time> | nullassigned_bystring | nullIdentifier
created_bystring | nullIdentifier
image_idstring | nullIdentifier
primary_document_idstring | nullIdentifier
image_urlstring<uri> | nullprofile_urlstring<uri> | nullAbsolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.
statusstringstatus_changed_atstring<date-time> | nullworkflow_idstring | nullIdentifier
candidate_workflow_idstring | nullIdentifier
active_candidate_countinteger<int32>Number of candidates on this job who are still in play: their workflow phase status is neither a placement (is_final) nor a rejection (hide_content). Candidates with no phase status are included. Always present; 0 when the job has no candidates.
rejected_candidate_countinteger<int32>Number of candidates on this job whose workflow phase status is a rejection or drop-out phase. Placed candidates are excluded even when their phase carries the same flag. Always present; 0 when none.
workflow_phase_statusstring | nullName of the workflow phase the record is currently in. Null when the record is not in a workflow phase.
workflow_stage_statusstring | nullName of the workflow stage that owns the current phase. Null when the record is not in a workflow phase or the phase has no stage.
workflow_phase_status_changed_atstring<date-time> | nullWhen the record last entered its current workflow phase. Null when the phase has never been set.
typesArray<string>Prefixed identifiers of the types linked to this job. Empty array when none.
contactsArray<string>Prefixed identifiers of the contacts linked to this job, primary contact first, capped at 100. Empty array when none. Resolve them with values=true, or fetch full contact objects from GET /v4/records/jobs/{id}/contacts.
aliasArray<string>Alternative names stored for this record, oldest first. Empty array when none.
[key: string]string | Array<string>{
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
}JobObjects
objectprimary_locationobject | nullsourceobject | nullflowobject | nullcompanyobject | nullnotesArray<object>Included notes array (newest-first, max 25). Empty array when no notes.
{
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
}JobData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredBase job fields plus custom field values keyed by field slug. Scalar custom fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings. The derived active_candidate_count and rejected_candidate_count attributes are integers.
objectsobjectrequiredvaluesobjectOptional per-item hydrated values keyed by attributes field. Present only when values=true is requested. Scalar reference attributes hydrate to one public object summary; array attributes hydrate to an array of summaries, including empty and one-member arrays.
custom_field_formatsobjectrequiredText custom-field render formats keyed by field slug. Values are plain, markdown, or html.
{
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}JobCreateData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredBase job fields plus custom field values keyed by field slug. Scalar custom fields, single_select, one_to_one, image, and file values are string or null; multiple_select and one_to_many values are arrays of strings. The derived active_candidate_count and rejected_candidate_count attributes are integers.
custom_field_formatsobjectrequiredText custom-field render formats keyed by field slug. Values are plain, markdown, or html.
{
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}JobResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
}JobsListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"objects": {
"primary_location": {
"id": "vM7Lp2q",
"type": "location",
"attributes": {
"formatted": "Prinsengracht 263, 1016 GV Amsterdam, Netherlands",
"is_primary": true,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"source": {
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"name": "LinkedIn",
"url_id": "linkedin",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"flow": {
"id": "vM7Lp2q",
"type": "job_flow",
"attributes": {
"phase_status_id": "vM7Lp2q",
"created_by": "vM7Lp2q",
"last_status_changed_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"company": {
"id": "vM7Lp2q",
"type": "company",
"attributes": {
"name": "Acme AB",
"image_url": "https://example.com",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
},
"notes": [
{
"id": "xYz123Ab",
"type": "note",
"attributes": {
"title": "Call recap",
"text": "Spoke about Q3 roadmap.",
"type": "follow_up",
"created_by": "usr1Abc",
"last_edited_by": "usr2Def",
"created_at": "2026-04-25T10:00:00Z",
"updated_at": "2026-04-25T10:05:00Z"
}
}
]
},
"values": {},
"custom_field_formats": {}
}
]
}JobCreateResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "job",
"attributes": {
"name": "Senior Engineer",
"company_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z",
"address": "string",
"assigned_to": "vM7Lp2q",
"assigned_at": "2026-03-10T14:30:00Z",
"assigned_by": "vM7Lp2q",
"created_by": "vM7Lp2q",
"image_id": "vM7Lp2q",
"primary_document_id": "vM7Lp2q",
"image_url": "https://example.com",
"profile_url": "https://example.com",
"status": "normal",
"status_changed_at": "2026-03-10T14:30:00Z",
"workflow_id": "vM7Lp2q",
"candidate_workflow_id": "vM7Lp2q",
"active_candidate_count": 12,
"rejected_candidate_count": 34,
"workflow_phase_status": "Interview",
"workflow_stage_status": "Screening",
"workflow_phase_status_changed_at": "2026-03-10T14:30:00Z",
"types": [
"job_type:Xy3",
"job_type:Q9a"
],
"contacts": [
"job_contact:Xy3",
"job_contact:Q9a"
],
"alias": [
"Jane D.",
"J. Doe"
]
},
"custom_field_formats": {}
}
}SourceAttributes
objectparent_source_idstring | nullIdentifier
namestringdescriptionstring | nullcreated_atstring<date-time>updated_atstring<date-time>{
"parent_source_id": "vM7Lp2q",
"name": "LinkedIn",
"description": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}SourceData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"parent_source_id": "vM7Lp2q",
"name": "LinkedIn",
"description": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}SourcesListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "source",
"attributes": {
"parent_source_id": "vM7Lp2q",
"name": "LinkedIn",
"description": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}ListAttributes
objectnamestring | nullcolor_bgstring | nullcolor_textstring | nullis_archivedbooleancreated_atstring<date-time> | nullupdated_atstring<date-time> | null{
"name": "string",
"color_bg": "#3B82F6",
"color_text": "#FFFFFF",
"is_archived": false,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}ListData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "list",
"attributes": {
"name": "string",
"color_bg": "#3B82F6",
"color_text": "#FFFFFF",
"is_archived": false,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}ListResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "list",
"attributes": {
"name": "string",
"color_bg": "#3B82F6",
"color_text": "#FFFFFF",
"is_archived": false,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}ListsResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "list",
"attributes": {
"name": "string",
"color_bg": "#3B82F6",
"color_text": "#FFFFFF",
"is_archived": false,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}UserAttributes
objectnamestring | nullfull_namestring | nullemailstring | nullemail_verified_atstring<date-time> | nullphonestring | nullactivebooleanimage_idstring | nullIdentifier
image_urlstring | nullcreated_atstring<date-time>updated_atstring<date-time>{
"name": "string",
"full_name": "string",
"email": "string",
"email_verified_at": "2026-03-10T14:30:00Z",
"phone": "string",
"active": true,
"image_id": "vM7Lp2q",
"image_url": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}UserData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "user",
"attributes": {
"name": "string",
"full_name": "string",
"email": "string",
"email_verified_at": "2026-03-10T14:30:00Z",
"phone": "string",
"active": true,
"image_id": "vM7Lp2q",
"image_url": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}UserResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "user",
"attributes": {
"name": "string",
"full_name": "string",
"email": "string",
"email_verified_at": "2026-03-10T14:30:00Z",
"phone": "string",
"active": true,
"image_id": "vM7Lp2q",
"image_url": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}UsersListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "user",
"attributes": {
"name": "string",
"full_name": "string",
"email": "string",
"email_verified_at": "2026-03-10T14:30:00Z",
"phone": "string",
"active": true,
"image_id": "vM7Lp2q",
"image_url": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}WorkflowPhaseAttributes
objectworkflow_idstring | nullIdentifier
stage_idstring | nullIdentifier
statusstringorderinteger<int32>colorstringhide_contentbooleanis_finalbooleanavailable_in_draft_listbooleanmax_daysinteger<int32> | nullcreated_atstring<date-time>updated_atstring<date-time>{
"workflow_id": "vM7Lp2q",
"stage_id": "vM7Lp2q",
"status": "Active",
"order": 1,
"color": "#00FF00",
"hide_content": false,
"is_final": false,
"available_in_draft_list": true,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}WorkflowPhaseData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "workflow-phase",
"attributes": {
"workflow_id": "vM7Lp2q",
"stage_id": "vM7Lp2q",
"status": "Active",
"order": 1,
"color": "#00FF00",
"hide_content": false,
"is_final": false,
"available_in_draft_list": true,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}WorkflowPhasesListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "workflow-phase",
"attributes": {
"workflow_id": "vM7Lp2q",
"stage_id": "vM7Lp2q",
"status": "Active",
"order": 1,
"color": "#00FF00",
"hide_content": false,
"is_final": false,
"available_in_draft_list": true,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}WorkflowStageAttributes
objectworkflow_idstring | nullIdentifier
statusstringorderinteger<int32>colorstring | nullcolor_bgstring | nullcolor_textstring | nullcompletion_expected_percentageinteger<int32> | nullmax_daysinteger<int32> | nullcreated_atstring<date-time>updated_atstring<date-time>{
"workflow_id": "vM7Lp2q",
"status": "Screening",
"order": 1,
"color": "#3B82F6",
"color_bg": "#EFF6FF",
"color_text": "#1E40AF",
"completion_expected_percentage": 25,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}WorkflowStageData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "workflow-stage",
"attributes": {
"workflow_id": "vM7Lp2q",
"status": "Screening",
"order": 1,
"color": "#3B82F6",
"color_bg": "#EFF6FF",
"color_text": "#1E40AF",
"completion_expected_percentage": 25,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}WorkflowStagesListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "workflow-stage",
"attributes": {
"workflow_id": "vM7Lp2q",
"status": "Screening",
"order": 1,
"color": "#3B82F6",
"color_bg": "#EFF6FF",
"color_text": "#1E40AF",
"completion_expected_percentage": 25,
"max_days": 0,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}WorkflowAttributes
objectnamestring | nullfor_item_typestring | nullcreated_atstring<date-time>updated_atstring<date-time>{
"name": "Hiring Pipeline",
"for_item_type": "job_candidate",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}WorkflowData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "workflow",
"attributes": {
"name": "Hiring Pipeline",
"for_item_type": "job_candidate",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}WorkflowsListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "workflow",
"attributes": {
"name": "Hiring Pipeline",
"for_item_type": "job_candidate",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}SetSourceData
objectitem_typestringrequireditem_idstringrequiredIdentifier
source_idstringrequiredIdentifier
{
"item_type": "person",
"item_id": "vM7Lp2q",
"source_id": "vM7Lp2q"
}SetSourceResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"source_id": "vM7Lp2q"
}
}SetWorkflowPhaseData
objectitem_typestringrequireditem_idstringrequiredIdentifier
person_idstring | nullIdentifier
workflow_idstringrequiredIdentifier
phase_status_idstringrequiredIdentifier
log_idstring | nullIdentifier
{
"item_type": "person",
"item_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"workflow_id": "vM7Lp2q",
"phase_status_id": "vM7Lp2q",
"log_id": "vM7Lp2q"
}SetWorkflowPhaseResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"item_type": "person",
"item_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"workflow_id": "vM7Lp2q",
"phase_status_id": "vM7Lp2q",
"log_id": "vM7Lp2q"
}
}AddJobContactData
objectidstringrequiredIdentifier
job_idstringrequiredIdentifier
person_idstringrequiredIdentifier
is_primarybooleanrequirednotestring | null{
"id": "vM7Lp2q",
"job_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string"
}JobContactAttributes
objectperson_idstring | nullIdentifier
is_primarybooleannotestring | nullcreated_atstring<date-time>updated_atstring<date-time>{
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}JobContactPersonObject
objectidstringIdentifier
namestring | nullimage_urlstring | null{
"id": "vM7Lp2q",
"name": "string",
"image_url": "string"
}JobContactObjects
objectpersonobject | null{
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string"
}
}JobContactData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredobjectsobject{
"id": "vM7Lp2q",
"type": "job_contact",
"attributes": {
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string"
}
}
}JobContactsListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job_contact",
"attributes": {
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string"
}
}
}
]
}AddJobContactResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"job_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string"
}
}UpdateJobContactResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"job_id": "vM7Lp2q",
"person_id": "vM7Lp2q",
"is_primary": false,
"note": "string"
}
}JobCandidatePersonObject
objectidstringIdentifier
namestring | nullimage_urlstring | nullemail_addressstring | null{
"id": "vM7Lp2q",
"name": "string",
"image_url": "string",
"email_address": "string"
}JobCandidateObjects
objectpersonobject | null{
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string",
"email_address": "string"
}
}JobCandidateAttributes
objectperson_idstring | nullIdentifier
status_idstring | nullIdentifier
rankinginteger<int32> | nullCandidate ranking
created_bystring | nullIdentifier
last_status_changed_atstring<date-time> | nulllast_status_changed_bystring | nullIdentifier
created_atstring<date-time>requiredupdated_atstring<date-time>required{
"person_id": "vM7Lp2q",
"status_id": "vM7Lp2q",
"ranking": 0,
"created_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"last_status_changed_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}JobCandidateData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredobjectsobject{
"id": "vM7Lp2q",
"type": "job_candidate",
"attributes": {
"person_id": "vM7Lp2q",
"status_id": "vM7Lp2q",
"ranking": 0,
"created_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"last_status_changed_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string",
"email_address": "string"
}
}
}JobCandidatesListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "job_candidate",
"attributes": {
"person_id": "vM7Lp2q",
"status_id": "vM7Lp2q",
"ranking": 0,
"created_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"last_status_changed_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string",
"email_address": "string"
}
}
}
]
}JobCandidateResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "job_candidate",
"attributes": {
"person_id": "vM7Lp2q",
"status_id": "vM7Lp2q",
"ranking": 0,
"created_by": "vM7Lp2q",
"last_status_changed_at": "2026-03-10T14:30:00Z",
"last_status_changed_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"person": {
"id": "vM7Lp2q",
"name": "string",
"image_url": "string",
"email_address": "string"
}
}
}
}UploadFileData
objectidstringrequiredIdentifier
filenamestringrequiredmimestringrequiredsizeinteger<int32>requiredFile size in bytes
{
"id": "vM7Lp2q",
"filename": "cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400
}UploadFileResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400
}
}UploadImageData
objectidstringrequiredIdentifier
filenamestringrequiredmimestringrequiredsizeinteger<int32>requiredImage size in bytes
{
"id": "vM7Lp2q",
"filename": "headshot.jpg",
"mime": "image/jpeg",
"size": 204800
}UploadImageResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"filename": "headshot.jpg",
"mime": "image/jpeg",
"size": 204800
}
}AliasAttributes
objectaliasstringrequiredAlias text
created_atstring<date-time>requiredupdated_atstring<date-time>required{
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}AliasObject
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}AliasResponse
objectstatusstringrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}AliasListResponse
objectstatusstringrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "alias",
"attributes": {
"alias": "ACME Corp",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}DeleteAliasResponse
objectstatusstringrequireddataobjectrequired{
"status": "ok",
"data": {
"deleted": true,
"alias_id": "vM7Lp2q"
}
}BookmarkAttributes
objecturlstringrequiredBookmark URL
titlestring | nullBookmark title
commentstring | nullOptional comment
created_atstring<date-time>requiredupdated_atstring<date-time>required{
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}BookmarkObject
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}BookmarkResponse
objectstatusstringrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}BookmarkListResponse
objectstatusstringrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "bookmark",
"attributes": {
"url": "https://example.com",
"title": "Example site",
"comment": "string",
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}CreateBookmarkRequest
objecturlstringrequiredBookmark URL
titlestring | nullBookmark title
commentstring | nullOptional comment
{
"url": "https://example.com",
"title": "Example site",
"comment": "string"
}DeleteBookmarkResponse
objectstatusstringrequireddataobjectrequired{
"status": "ok",
"data": {
"deleted": true,
"bookmark_id": "vM7Lp2q"
}
}FileItem
objectidstringIdentifier
typestringfileattributesobject{
"id": "vM7Lp2q",
"type": "file",
"attributes": {
"name": "CV John Doe",
"filename": "abc123_cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}FileListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "file",
"attributes": {
"name": "CV John Doe",
"filename": "abc123_cv_john_doe.pdf",
"mime": "application/pdf",
"size": 102400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}ImageItem
objectidstringIdentifier
typestringimageattributesobject{
"id": "vM7Lp2q",
"type": "image",
"attributes": {
"name": "Headshot",
"filename": "abc123_headshot.jpg",
"mime": "image/jpeg",
"size": 204800,
"width": 400,
"height": 400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}ImageListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "image",
"attributes": {
"name": "Headshot",
"filename": "abc123_headshot.jpg",
"mime": "image/jpeg",
"size": 204800,
"width": 400,
"height": 400,
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}CommunicationAttributes
objectsubjectstring | nullsummarystring | nullmethod_idstring | nullIdentifier
datestring<date> | nullThe day the communication took place (YYYY-MM-DD). Null when unset.
created_bystring | nullIdentifier
created_atstring<date-time>updated_atstring<date-time>{
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}CommunicationMethodObject
objectidstringrequiredIdentifier
namestring | nullrequired{
"id": "vM7Lp2q",
"name": "Phone"
}CommunicationObjects
objectmethodobject | null{
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}CommunicationData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredobjectsobject{
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}CommunicationsListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}
]
}CommunicationResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "communication",
"attributes": {
"subject": "Follow-up call",
"summary": "Discussed the Q3 interview schedule.",
"method_id": "vM7Lp2q",
"date": "2026-07-02",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"objects": {
"method": {
"id": "vM7Lp2q",
"name": "Phone"
}
}
}
}EmailAddress
objectnamestring | nullrequiredemailstring<email> | nullrequired{
"name": "Jane",
"email": "jane@example.com"
}EmailAttachment
objectidstringrequiredIdentifier
namestring | nullrequiredfile_namestring | nullrequiredmimestring | nullrequiredsizeinteger<int32> | nullrequiredcreated_atstring<date-time> | nullrequired{
"id": "vM7Lp2q",
"name": "cv.pdf",
"file_name": "cv.pdf",
"mime": "application/pdf",
"size": 12345,
"created_at": "2026-03-10T14:30:00Z"
}EmailAttributes
objectsubjectstring | nulltextstring | nullhtmlstring | nulltoArray<object>fromArray<object>ccArray<object>bccArray<object>labelsArray<string>message_idstring | nulluser_idstring | nullIdentifier
is_privatebooleanis_readbooleanis_archivedbooleansent_atstring<date-time> | nullattachmentsArray<object>{
"subject": "Follow-up",
"text": "Plain text email body",
"html": "<p>HTML email body</p>",
"to": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"from": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"cc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"bcc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"labels": [
"inbox"
],
"message_id": "<message@example.com>",
"user_id": "vM7Lp2q",
"is_private": false,
"is_read": false,
"is_archived": false,
"sent_at": "2026-03-10T14:30:00Z",
"attachments": [
{
"id": "vM7Lp2q",
"name": "cv.pdf",
"file_name": "cv.pdf",
"mime": "application/pdf",
"size": 12345,
"created_at": "2026-03-10T14:30:00Z"
}
]
}EmailData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "email",
"attributes": {
"subject": "Follow-up",
"text": "Plain text email body",
"html": "<p>HTML email body</p>",
"to": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"from": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"cc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"bcc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"labels": [
"inbox"
],
"message_id": "<message@example.com>",
"user_id": "vM7Lp2q",
"is_private": false,
"is_read": false,
"is_archived": false,
"sent_at": "2026-03-10T14:30:00Z",
"attachments": [
{
"id": "vM7Lp2q",
"name": "cv.pdf",
"file_name": "cv.pdf",
"mime": "application/pdf",
"size": 12345,
"created_at": "2026-03-10T14:30:00Z"
}
]
}
}EmailsListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "email",
"attributes": {
"subject": "Follow-up",
"text": "Plain text email body",
"html": "<p>HTML email body</p>",
"to": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"from": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"cc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"bcc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"labels": [
"inbox"
],
"message_id": "<message@example.com>",
"user_id": "vM7Lp2q",
"is_private": false,
"is_read": false,
"is_archived": false,
"sent_at": "2026-03-10T14:30:00Z",
"attachments": [
{
"id": "vM7Lp2q",
"name": "cv.pdf",
"file_name": "cv.pdf",
"mime": "application/pdf",
"size": 12345,
"created_at": "2026-03-10T14:30:00Z"
}
]
}
}
]
}EmailResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "email",
"attributes": {
"subject": "Follow-up",
"text": "Plain text email body",
"html": "<p>HTML email body</p>",
"to": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"from": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"cc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"bcc": [
{
"name": "Jane",
"email": "jane@example.com"
}
],
"labels": [
"inbox"
],
"message_id": "<message@example.com>",
"user_id": "vM7Lp2q",
"is_private": false,
"is_read": false,
"is_archived": false,
"sent_at": "2026-03-10T14:30:00Z",
"attachments": [
{
"id": "vM7Lp2q",
"name": "cv.pdf",
"file_name": "cv.pdf",
"mime": "application/pdf",
"size": 12345,
"created_at": "2026-03-10T14:30:00Z"
}
]
}
}
}CommentAttributes
objecttextstring | nulluser_idstring | nullIdentifier
created_atstring<date-time>updated_atstring<date-time>{
"text": "Great candidate!",
"user_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}CommentData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "comment",
"attributes": {
"text": "Great candidate!",
"user_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}TodoCommentImage
objectidstringrequiredIdentifier
image_urlstring<uri>requiredfull_image_urlstring<uri>requirednamestringrequired{
"id": "vM7Lp2q",
"image_url": "https://img.example.test/acme/image-id?width=160",
"full_image_url": "https://img.example.test/acme/image-id",
"name": "Screenshot"
}TodoCommentData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequiredimagesArray<object>required{
"id": "vM7Lp2q",
"type": "comment",
"attributes": {
"text": "Great candidate!",
"user_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
},
"images": [
{
"id": "vM7Lp2q",
"image_url": "https://img.example.test/acme/image-id?width=160",
"full_image_url": "https://img.example.test/acme/image-id",
"name": "Screenshot"
}
]
}TodoCommentsResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {}
}CommentsListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "comment",
"attributes": {
"text": "Great candidate!",
"user_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}CommentResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "comment",
"attributes": {
"text": "Great candidate!",
"user_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}NoteRecordAttributes
objecttitlestring | nulltextstring | nullcreated_bystring | nullIdentifier
last_edited_bystring | nullIdentifier
created_atstring<date-time>updated_atstring<date-time>{
"title": "Interview notes",
"text": "Strong communication skills...",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}NoteData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "note",
"attributes": {
"title": "Interview notes",
"text": "Strong communication skills...",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}NotesListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "note",
"attributes": {
"title": "Interview notes",
"text": "Strong communication skills...",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}NoteResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "note",
"attributes": {
"title": "Interview notes",
"text": "Strong communication skills...",
"created_by": "vM7Lp2q",
"last_edited_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}CommunicationMethodData
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "communication_method",
"attributes": {
"name": "Phone"
}
}CommunicationMethodsListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "communication_method",
"attributes": {
"name": "Phone"
}
}
]
}CommunicationMethodResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "communication_method",
"attributes": {
"name": "Phone"
}
}
}WorkHistoryAttributes
objectperson_idstring | nullIdentifier
company_idstring | nullIdentifier
company_namestring | nullCompany name (free text if no company linked)
work_titlestring | nullJob title at this position
is_currentbooleanrequiredWhether this is the current position
is_primary_contactbooleanrequiredWhether this is the primary contact role
created_atstring<date-time>requiredupdated_atstring<date-time>required{
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}WorkHistoryObject
objectidstringrequiredIdentifier
typestringrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "work_history",
"attributes": {
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}WorkHistoryResponse
objectstatusstringrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "work_history",
"attributes": {
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
}WorkHistoryListResponse
objectstatusstringrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "work_history",
"attributes": {
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": false,
"is_primary_contact": false,
"created_at": "2026-01-15T09:00:00Z",
"updated_at": "2026-01-15T09:00:00Z"
}
}
]
}CreateWorkHistoryRequest
objectperson_idstringrequiredIdentifier
company_idstring | nullIdentifier
company_namestring | nullCompany name if no linked company
work_titlestring | nullJob title
is_currentboolean | nullCurrent position flag
is_primary_contactboolean | nullPrimary contact flag
{
"person_id": "vM7Lp2q",
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}UpdateWorkHistoryRequest
objectcompany_idstring | nullIdentifier
company_namestring | nullCompany name if no linked company
work_titlestring | nullJob title
is_currentboolean | nullCurrent position flag
is_primary_contactboolean | nullPrimary contact flag
{
"company_id": "vM7Lp2q",
"company_name": "string",
"work_title": "string",
"is_current": true,
"is_primary_contact": true
}DeleteWorkHistoryResponse
objectstatusstringrequireddataobjectrequired{
"status": "ok",
"data": {
"deleted": true,
"id": "vM7Lp2q"
}
}CategoryGroupAttributes
objectnamestring | nullrequiredcreated_atstring<date-time>updated_atstring<date-time>{
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}CategoryGroupObject
objectidstringrequiredIdentifier
typestringcategory_grouprequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "category_group",
"attributes": {
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}CategoryGroupResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category_group",
"attributes": {
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}CategoryGroupListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "category_group",
"attributes": {
"name": "utm_source",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}CreateCategoryGroupRequest
objectnamestringrequiredCategory group name
{
"name": "utm_source"
}UpdateCategoryGroupRequest
objectnamestringrequiredNew category group name
{
"name": "utm_source"
}CategoryAttributes
objectnamestring | nullrequiredgroup_idstringrequiredOwning category group ID
created_atstring<date-time>updated_atstring<date-time>{
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}CategoryObject
objectidstringrequiredIdentifier
typestringcategoryrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}CategoryResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}CategoryListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "category",
"attributes": {
"name": "newsletter",
"group_id": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}CreateCategoryRequest
objectnamestringrequiredCategory name
group_idstringrequiredOwning category group ID
{
"name": "newsletter",
"group_id": "vM7Lp2q"
}AddCategoryRequest
objectcategory_idstringrequiredCategory ID to link to the record
{
"category_id": "vM7Lp2q"
}DeleteCategoryLinkResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"deleted": true,
"category_id": "vM7Lp2q"
}
}TodoAttributes
objecttextstring | nullowner_typestring | nullowner_idstring | nullIdentifier
assigned_tostring | nullIdentifier
created_bystring | nullIdentifier
completed_bystring | nullIdentifier
list_idstring | nullIdentifier
label_idsArray<string>is_priority_taskbooleandue_atstring<date-time> | nullcompleted_atstring<date-time> | nullcreated_atstring<date-time> | nullupdated_atstring<date-time> | null{
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}TodoObject
objectidstringrequiredIdentifier
typestringtodorequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}TodoResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}TodoListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo",
"attributes": {
"text": "Follow up with candidate",
"owner_type": "person",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"completed_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": false,
"due_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}TodoBoardAttributes
objectnamestring | nullcreated_bystring | nullIdentifier
created_atstring<date-time> | nullupdated_atstring<date-time> | null{
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}TodoBoardObject
objectidstringrequiredIdentifier
typestringtodo_boardrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}TodoBoardResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}TodoBoardListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_board",
"attributes": {
"name": "Recruiting",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}TodoBoardListAttributes
objectboard_idstring | nullIdentifier
namestring | nulltext_colorstring | nullbackground_colorstring | nullcreated_bystring | nullIdentifier
created_atstring<date-time> | nullupdated_atstring<date-time> | null{
"board_id": "vM7Lp2q",
"name": "Doing",
"text_color": "#ffffff",
"background_color": "#0f766e",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}TodoBoardListObject
objectidstringrequiredIdentifier
typestringtodo_board_listrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "todo_board_list",
"attributes": {
"board_id": "vM7Lp2q",
"name": "Doing",
"text_color": "#ffffff",
"background_color": "#0f766e",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}TodoBoardListItemResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_board_list",
"attributes": {
"board_id": "vM7Lp2q",
"name": "Doing",
"text_color": "#ffffff",
"background_color": "#0f766e",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}TodoBoardListListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_board_list",
"attributes": {
"board_id": "vM7Lp2q",
"name": "Doing",
"text_color": "#ffffff",
"background_color": "#0f766e",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}TodoLabelAttributes
objectnamestring | nulltext_colorstring | nullbackground_colorstring | nullcreated_bystring | nullIdentifier
created_atstring<date-time> | nullupdated_atstring<date-time> | null{
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}TodoLabelObject
objectidstringrequiredIdentifier
typestringtodo_labelrequiredattributesobjectrequired{
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}TodoLabelResponse
objectstatusstringokrequireddataobjectrequired{
"status": "ok",
"data": {
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
}TodoLabelListResponse
objectstatusstringokrequireddataArray<object>required{
"status": "ok",
"data": [
{
"id": "vM7Lp2q",
"type": "todo_label",
"attributes": {
"name": "Urgent",
"text_color": "#ffffff",
"background_color": "#dc2626",
"created_by": "vM7Lp2q",
"created_at": "2026-03-10T14:30:00Z",
"updated_at": "2026-03-10T14:30:00Z"
}
}
]
}CreateTodoRequest
objecttextstringrequiredowner_typestring | nullowner_idstring | nullIdentifier
assigned_tostring | nullIdentifier
created_bystring | nullIdentifier
list_idstring | nullIdentifier
label_idsArray<string>is_priority_taskboolean | nulldue_atstring<date-time> | null{
"text": "Follow up with candidate",
"owner_type": "string",
"owner_id": "vM7Lp2q",
"assigned_to": "vM7Lp2q",
"created_by": "vM7Lp2q",
"list_id": "vM7Lp2q",
"label_ids": [
"vM7Lp2q"
],
"is_priority_task": true,
"due_at": "2026-03-10T14:30:00Z"
}UpdateTodoRequest
objecttextstring | nullis_priority_taskboolean | nulldue_atstring<date-time> | null{
"text": "string",
"is_priority_task": true,
"due_at": "2026-03-10T14:30:00Z"
}AssignTodoOwnerRequest
objectowner_typestringrequiredowner_idstringrequiredIdentifier
{
"owner_type": "string",
"owner_id": "vM7Lp2q"
}CreateTodoBoardRequest
objectnamestringrequiredcreated_bystring | nullIdentifier
{
"name": "string",
"created_by": "vM7Lp2q"
}CreateTodoBoardListRequest
objectnamestringrequiredtext_colorstring | nullbackground_colorstring | nullcreated_bystring | nullIdentifier
{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "vM7Lp2q"
}UpdateTodoBoardListRequest
objectnamestring | nulltext_colorstring | nullbackground_colorstring | null{
"name": "string",
"text_color": "string",
"background_color": "string"
}CreateTodoLabelRequest
objectnamestringrequiredtext_colorstring | nullbackground_colorstring | nullcreated_bystring | nullIdentifier
{
"name": "string",
"text_color": "string",
"background_color": "string",
"created_by": "vM7Lp2q"
}UpdateTodoLabelRequest
objectnamestring | nulltext_colorstring | nullbackground_colorstring | null{
"name": "string",
"text_color": "string",
"background_color": "string"
}OkResponse
objectstatusstringokrequireddatastring | nullAlways null for delete responses
{
"status": "ok",
"data": "string"
}ErrorBody
objectcodestringrequiredStable machine-readable error code.
status_codeinteger<int32>requiredHTTP status code for this response.
messagestringrequiredHuman-readable error message.
{
"code": "string",
"status_code": 0,
"message": "string"
}ErrorResponse
objectstatusstringerrorrequirederrorobjectrequired{
"status": "error",
"error": {
"code": "string",
"status_code": 0,
"message": "string"
}
}RecordSearchFilterClause
objectfieldstringrequiredopstringrequiredvalueany{
"field": "status",
"op": "contains"
}RecordSearchFilterGroup
objectopstringrequiredclausesArray<object>required{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}RecordSearchSort
objectfieldstringrequireddirectionstringrequired{
"field": "created_at",
"direction": "desc"
}SearchRecordsRequest
objectquerystringSearch query. Blank or omitted values default to match-all.
limitinteger<int32>Maximum results. Defaults to 10 and is clamped to 1-200.
offsetinteger<int32>Zero-based offset. Defaults to 0 and negative values clamp to 0.
filtersArray<object>Additional filter groups.
sortArray<object>Sort fields. Empty or omitted values default to created_at desc.
{
"query": "*",
"limit": 10,
"offset": 0,
"filters": [
{
"op": "and",
"clauses": [
{
"field": "status",
"op": "contains"
}
]
}
],
"sort": [
{
"field": "created_at",
"direction": "desc"
}
]
}TodoSearchHit
objectidstringrequiredPublic todo SqID stored in the index metadata.
scorenumber<float>requiredattributesobjectrequired{
"id": "encoded-todo-sqid",
"score": 0.75,
"attributes": {}
}