Home

SearchSoftware Public API

v4.0.0

Contact: support@sres.nl

Base URL
https://api.searchsoftware.nlProduction

The 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.

ScopeGrants
people:readRead people
people:writeCreate / update people
companies:readRead companies
companies:writeCreate / update companies
jobs:readRead jobs
jobs:writeCreate / update jobs
files:readDownload files (also needs the record's read scope)
files:writeReserved for future file write access
sources:readRead sources
sources:writeCreate / update sources and source groups
workflows:readRead workflow phases and stages
workflows:writeSet workflow phase on a record
users:readRead users
users:writeCreate / update users
communications:readRead communications and methods
communications:writeCreate communications and methods
comments:readRead comments
comments:writeCreate comments
notes:readRead notes
notes:writeCreate notes
categories:readRead categories and category groups
categories:writeCreate / update categories and category groups
work_history:readRead work history entries
work_history:writeCreate / update work history entries
todos:readRead todos, todo boards, board lists, and labels
todos:writeCreate / 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.

ResourceAvailable includes
peopleprimary_email, primary_phone, primary_location, source, notes, flow
companiesprimary_email, primary_phone, primary_location, source, notes, flow
jobsprimary_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_authhttp

API key in Authorization header

Scheme: bearer

apikey_authapiKey

API 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

GET
https://api.searchsoftware.nl/v4/records/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

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

sort_orderstringquery

Sort by created_at: asc or desc (default desc)

includestringquery

Optional includes: primary_email, primary_phone, primary_location, source, notes, flow

valuesstringquery

Set 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

200OKobject

People list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List people
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

POST
https://api.searchsoftware.nl/v4/records/people

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

application/json
namestringrequired

Full name

email_addressstringrequired

Primary email address

phone_numberstring

Phone number

work_titlestring

Work title

company_idstring

company ID

assigned_tostring

user ID to assign the person to

created_bystring

user ID of the record creator

assigned_bystring

user ID of the assigner

genderstring

Gender

workflow_idstring

workflow ID to attach on creation

workflow_phase_idstring

Workflow phase ID to place the new person in. Requires workflow_id. Must belong to that workflow. Defaults to the first phase when omitted.

streetstring

Street address

zipstring

Postal or ZIP code

citystring

City

country_codestring

ISO country code

birthdatestring

Birthdate in YYYY-MM-DD format

primary_document_idstring

file ID for the primary document

typesarray

Array of person type string identifiers (e.g. ["candidate", "contact"])

custom_fieldsobject

Object 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

200OKobject

Person created

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Create a person
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(())
}
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": {}
}
{
  "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

POST
https://api.searchsoftware.nl/v4/records/people/get-many

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

application/json
idsarrayrequired

Array of record IDs to fetch (max 100)

Parameters

includestringquery

Optional includes: source, notes, flow

valuesstringquery

Set 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

200OKobject

Get people by IDs results

400Bad Requestobject

Invalid id in request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Too many ids or invalid request body

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

Get people by IDs
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/people/{id}

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

idstringrequiredpath

Person ID

includestringquery

Optional includes: primary_email, primary_phone, primary_location, source, notes, flow

valuesstringquery

Set 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

200OKobject

Person found

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

Get a person
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

PATCH
https://api.searchsoftware.nl/v4/records/people/{id}

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

application/json
namestring

New record name. For jobs this updates the title.

custom_fieldsobject

Custom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.

Show child attributes
[key: string]any

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

Record updated

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

No changes, invalid name, unknown field, or validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Update a person
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/people/{id}/jobs

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

idstringrequiredpath

Person ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Jobs list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List jobs for a person
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

PUT
https://api.searchsoftware.nl/v4/records/people/{id}/source

Assigns a source to a person. Requires people:write.

Body

application/json
source_idstringrequired

Source ID

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

Source set

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Set person source
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/records/people/{id}/workflow-phase

Sets a workflow phase on a person. Requires people:write.

Body

application/json
workflow_idstringrequired

Workflow ID

phase_status_idstringrequired

Phase status ID

notestring

Optional note

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

Workflow phase set

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Set person workflow phase
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/people/{id}/aliases

Returns all aliases attached to the person. Requires people:read.

Parameters

idstringrequiredpath

Person ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Alias list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List aliases for a person
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

POST
https://api.searchsoftware.nl/v4/records/people/{id}/aliases

Creates a new alias for the person. Duplicate aliases for the same person are rejected (case-insensitive). Requires people:write.

Body

application/json
aliasstringrequired

Alias text

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

Alias created

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

422Unprocessable Entityobject

Validation failed or duplicate alias

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Add an alias to a person
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/records/people/{id}/aliases/{alias_id}

Removes an alias from the person. Requires people:write.

Parameters

idstringrequiredpath

Person ID

alias_idstringrequiredpath

Alias ID

Response

200OKobject

Alias deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person or alias not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Delete an alias from a person
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

GET
https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks

Returns all bookmarks linked to the person. Requires people:read.

Parameters

idstringrequiredpath

Person ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Bookmark list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List bookmarks for a person
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

POST
https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks

Creates a new bookmark linked to the person. Requires people:write.

Body

application/json
urlstringrequired

Bookmark URL

titlestring

Bookmark title

commentstring

Optional comment

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

Bookmark created

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

422Unprocessable Entityobject

Validation failed

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Add a bookmark to a person
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/records/people/{id}/bookmarks/{bookmark_id}

Removes a bookmark from the person. Requires people:write.

Parameters

idstringrequiredpath

Person ID

bookmark_idstringrequiredpath

Bookmark ID

Response

200OKobject

Bookmark deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person or bookmark not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Delete a bookmark from a person
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

GET
https://api.searchsoftware.nl/v4/records/people/{id}/categories

Returns the categories linked to the person. Requires people:read.

Parameters

idstringrequiredpath

Person ID

limitstringquery

Max results, 1-100, default 50

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Category list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List categories for a person
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

POST
https://api.searchsoftware.nl/v4/records/people/{id}/categories

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

application/json
category_idstringrequired

Category ID to link

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

Category linked

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person or category not found

422Unprocessable Entityobject

Validation failed

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Add a category to a person
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/records/people/{id}/categories/{category_id}

Unlinks a category from the person. Idempotent: removing a category that is not linked is a success no-op. Requires people:write.

Parameters

idstringrequiredpath

Person ID

category_idstringrequiredpath

Category ID

Response

200OKobject

Category unlinked

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Remove a category from a person
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

GET
https://api.searchsoftware.nl/v4/records/people/{id}/files

Lists files attached to a person. Requires people:read.

Parameters

idstringrequiredpath

Person ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Files list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List files for a person
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

GET
https://api.searchsoftware.nl/v4/records/people/{id}/images

Lists images attached to a person. Requires people:read.

Parameters

idstringrequiredpath

Person ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Images list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List images for a person
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

GET
https://api.searchsoftware.nl/v4/records/people/{id}/communications

Lists communications attached to a person. Requires people:read.

Parameters

idstringrequiredpath

Person ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

includestringquery

Optional includes: method

Response

200OKobject

Communications list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:read

apikey_authapiKey in query

API key in query string

Scopes: people:read

List communications for a person
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

POST
https://api.searchsoftware.nl/v4/records/people/{id}/files/upload

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

multipart/form-data
filestring<binary>required

File binary data

primary_documentstring

Set to "true" to update primary document

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

File uploaded

400Bad Requestobject

Invalid id or no file provided

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Upload a file to a person
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/records/people/{id}/images/upload

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

multipart/form-data
filestring<binary>required

Image binary data

profile_picturestring

Set to "true" to update profile picture

Parameters

idstringrequiredpath

Person ID

Response

200OKobject

Image uploaded

400Bad Requestobject

Invalid id or no file provided

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: people:write

apikey_authapiKey in query

API key in query string

Scopes: people:write

Upload an image to a person
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/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

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

sort_orderstringquery

Sort by created_at: asc or desc (default desc)

includestringquery

Optional includes: primary_email, primary_phone, primary_location, source, notes, flow

valuesstringquery

Set 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

200OKobject

Companies list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

List companies
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

POST
https://api.searchsoftware.nl/v4/records/companies

Creates a company record. Requires companies:write. Create can set custom fields in the same format as PATCH.

Body

application/json
namestringrequired

Company name

created_bystring

user ID of the record creator

assigned_tostring

user ID to assign the company to

assigned_bystring

user ID of the assigner

workflow_idstring

workflow ID to attach on creation

workflow_phase_idstring

Workflow 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_idstring

file ID for the primary document

custom_fieldsobject

Object 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

200OKobject

Company created

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Create a company
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(())
}
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": {}
}
{
  "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

POST
https://api.searchsoftware.nl/v4/records/companies/get-many

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

application/json
idsarrayrequired

Array of record IDs to fetch (max 100)

Parameters

includestringquery

Optional includes: source, notes, flow

valuesstringquery

Set 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

200OKobject

Get companies by IDs results

400Bad Requestobject

Invalid id in request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Too many ids or invalid request body

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

Get companies by IDs
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/companies/{id}

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

idstringrequiredpath

Company ID

includestringquery

Optional includes: primary_email, primary_phone, primary_location, source, notes, flow

valuesstringquery

Set 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

200OKobject

Company found

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

Get a company
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

PATCH
https://api.searchsoftware.nl/v4/records/companies/{id}

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

application/json
namestring

New record name. For jobs this updates the title.

custom_fieldsobject

Custom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.

Show child attributes
[key: string]any

Parameters

idstringrequiredpath

Company ID

Response

200OKobject

Record updated

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

No changes, invalid name, unknown field, or validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Update a company
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/companies/{id}/jobs

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

idstringrequiredpath

Company ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Jobs list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

List jobs for a company
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

PUT
https://api.searchsoftware.nl/v4/records/companies/{id}/source

Assigns a source to a company. Requires companies:write.

Body

application/json
source_idstringrequired

Source ID

Parameters

idstringrequiredpath

Company ID

Response

200OKobject

Source set

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Set company source
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/records/companies/{id}/workflow-phase

Sets a workflow phase on a company. Requires companies:write.

Body

application/json
workflow_idstringrequired

Workflow ID

phase_status_idstringrequired

Phase status ID

notestring

Optional note

Parameters

idstringrequiredpath

Company ID

Response

200OKobject

Workflow phase set

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Set company workflow phase
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/companies/{id}/aliases

Returns all aliases attached to the company. Requires companies:read.

Parameters

idstringrequiredpath

Company ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Alias list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

List aliases for a company
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

POST
https://api.searchsoftware.nl/v4/records/companies/{id}/aliases

Creates a new alias for the company. Duplicate aliases for the same company are rejected (case-insensitive). Requires companies:write.

Body

application/json
aliasstringrequired

Alias text

Parameters

idstringrequiredpath

Company ID

Response

200OKobject

Alias created

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

422Unprocessable Entityobject

Validation failed or duplicate alias

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Add an alias to a company
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/records/companies/{id}/aliases/{alias_id}

Removes an alias from the company. Requires companies:write.

Parameters

idstringrequiredpath

Company ID

alias_idstringrequiredpath

Alias ID

Response

200OKobject

Alias deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company or alias not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Delete an alias from a company
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

GET
https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks

Returns all bookmarks linked to the company. Requires companies:read.

Parameters

idstringrequiredpath

Company ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Bookmark list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

List bookmarks for a company
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

POST
https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks

Creates a new bookmark linked to the company. Requires companies:write.

Body

application/json
urlstringrequired

Bookmark URL

titlestring

Bookmark title

commentstring

Optional comment

Parameters

idstringrequiredpath

Company ID

Response

200OKobject

Bookmark created

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

422Unprocessable Entityobject

Validation failed

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Add a bookmark to a company
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/records/companies/{id}/bookmarks/{bookmark_id}

Removes a bookmark from the company. Requires companies:write.

Parameters

idstringrequiredpath

Company ID

bookmark_idstringrequiredpath

Bookmark ID

Response

200OKobject

Bookmark deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company or bookmark not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Delete a bookmark from a company
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

GET
https://api.searchsoftware.nl/v4/records/companies/{id}/files

Lists files attached to a company. Requires companies:read.

Parameters

idstringrequiredpath

Company ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Files list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

List files for a company
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

GET
https://api.searchsoftware.nl/v4/records/companies/{id}/images

Lists images attached to a company. Requires companies:read.

Parameters

idstringrequiredpath

Company ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Images list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

List images for a company
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

GET
https://api.searchsoftware.nl/v4/records/companies/{id}/communications

Lists communications attached to a company. Requires companies:read.

Parameters

idstringrequiredpath

Company ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

includestringquery

Optional includes: method

Response

200OKobject

Communications list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Company not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:read

apikey_authapiKey in query

API key in query string

Scopes: companies:read

List communications for a company
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

POST
https://api.searchsoftware.nl/v4/records/companies/{id}/files/upload

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

multipart/form-data
filestring<binary>required

File binary data

primary_documentstring

Set to "true" to update primary document

Parameters

idstringrequiredpath

Company ID

Response

200OKobject

File uploaded

400Bad Requestobject

Invalid id or no file provided

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Upload a file to a company
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/records/companies/{id}/images/upload

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

multipart/form-data
filestring<binary>required

Image binary data

profile_picturestring

Set to "true" to update profile picture

Parameters

idstringrequiredpath

Company ID

Response

200OKobject

Image uploaded

400Bad Requestobject

Invalid id or no file provided

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: companies:write

apikey_authapiKey in query

API key in query string

Scopes: companies:write

Upload an image to a company
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/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

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

sort_orderstringquery

Sort by created_at: asc or desc (default desc)

includestringquery

Optional includes: primary_location, source, notes, flow, company

valuesstringquery

Set 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

200OKobject

Jobs list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List jobs
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

POST
https://api.searchsoftware.nl/v4/records/jobs

Creates a job record. Requires jobs:write. Create can set custom fields in the same format as PATCH.

Body

application/json
namestringrequired

Job name

company_idstringrequired

company ID to associate the job with

created_bystring

user ID of the record creator

assigned_tostring

user ID to assign the job to

assigned_bystring

user ID of the assigner

workflow_idstring

Job workflow ID to attach on creation

workflow_phase_idstring

Job-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_idstring

Candidate workflow ID to attach on creation

primary_document_idstring

file ID for the primary document

custom_fieldsobject

Object 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

200OKobject

Job created

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Create a job
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(())
}
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": {}
}
{
  "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

POST
https://api.searchsoftware.nl/v4/records/jobs/get-many

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

application/json
idsarrayrequired

Array of record IDs to fetch (max 100)

Parameters

includestringquery

Optional includes: source, notes, flow, company

valuesstringquery

Set 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

200OKobject

Get jobs by IDs results

400Bad Requestobject

Invalid id in request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Too many ids or invalid request body

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

Get jobs by IDs
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}

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

idstringrequiredpath

Job ID

includestringquery

Optional includes: primary_location, source, notes, flow, company

valuesstringquery

Set 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

200OKobject

Job found

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

Get a job
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

PATCH
https://api.searchsoftware.nl/v4/records/jobs/{id}

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

application/json
namestring

New record name. For jobs this updates the title.

custom_fieldsobject

Custom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.

Show child attributes
[key: string]any

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

Record updated

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

No changes, invalid name, unknown field, or validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Update a job
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/records/jobs/{id}/source

Assigns a source to a job. Requires jobs:write.

Body

application/json
source_idstringrequired

Source ID

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

Source set

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Set job source
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/records/jobs/{id}/workflow-phase

Sets a workflow phase on a job. Requires jobs:write.

Body

application/json
workflow_idstringrequired

Workflow ID

phase_status_idstringrequired

Phase status ID

notestring

Optional note

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

Workflow phase set

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Set job workflow phase
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{person_id}/workflow-phase

Sets a workflow phase on a candidate within a job. Requires jobs:write.

Body

application/json
workflow_idstringrequired

Workflow ID

phase_status_idstringrequired

Phase status ID

notestring

Optional note

Parameters

idstringrequiredpath

Job ID

person_idstringrequiredpath

Person ID

Response

200OKobject

Workflow phase set

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Set candidate workflow phase
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases

Returns all aliases attached to the job. Requires jobs:read.

Parameters

idstringrequiredpath

Job ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Alias list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List aliases for a job
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

POST
https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases

Creates a new alias for the job. Duplicate aliases for the same job are rejected (case-insensitive). Requires jobs:write.

Body

application/json
aliasstringrequired

Alias text

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

Alias created

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

422Unprocessable Entityobject

Validation failed or duplicate alias

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Add an alias to a job
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/records/jobs/{id}/aliases/{alias_id}

Removes an alias from the job. Requires jobs:write.

Parameters

idstringrequiredpath

Job ID

alias_idstringrequiredpath

Alias ID

Response

200OKobject

Alias deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job or alias not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Delete an alias from a job
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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks

Returns all bookmarks linked to the job. Requires jobs:read.

Parameters

idstringrequiredpath

Job ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Bookmark list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List bookmarks for a job
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

POST
https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks

Creates a new bookmark linked to the job. Requires jobs:write.

Body

application/json
urlstringrequired

Bookmark URL

titlestring

Bookmark title

commentstring

Optional comment

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

Bookmark created

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

422Unprocessable Entityobject

Validation failed

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Add a bookmark to a job
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/records/jobs/{id}/bookmarks/{bookmark_id}

Removes a bookmark from the job. Requires jobs:write.

Parameters

idstringrequiredpath

Job ID

bookmark_idstringrequiredpath

Bookmark ID

Response

200OKobject

Bookmark deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job or bookmark not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Delete a bookmark from a job
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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/files

Lists files attached to a job. Requires jobs:read.

Parameters

idstringrequiredpath

Job ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Files list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List files for a job
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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/images

Lists images attached to a job. Requires jobs:read.

Parameters

idstringrequiredpath

Job ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Images list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List images for a job
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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/communications

Lists communications attached to a job. Requires jobs:read.

Parameters

idstringrequiredpath

Job ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

includestringquery

Optional includes: method

Response

200OKobject

Communications list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List communications for a job
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

POST
https://api.searchsoftware.nl/v4/records/jobs/{id}/files/upload

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

multipart/form-data
filestring<binary>required

File binary data

primary_documentstring

Set to "true" to update primary document

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

File uploaded

400Bad Requestobject

Invalid id or no file provided

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Upload a file to a job
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/records/jobs/{id}/images/upload

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

multipart/form-data
filestring<binary>required

Image binary data

profile_picturestring

Set to "true" to update profile picture

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

Image uploaded

400Bad Requestobject

Invalid id or no file provided

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Upload an image to a job
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/files/{id}/download

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

idstringrequiredpath

File ID

dispositionstringquery

attachment (default) or inline

Response

200OKstring<binary>

File bytes

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

File not found, unlinked, or with no stored content

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: files:read

apikey_authapiKey in query

API key in query string

Scopes: files:read

Download a file
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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts

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

idstringrequiredpath

Job ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

includestringquery

Optional includes: person

Response

200OKobject

Job contacts list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List contacts for a job
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

POST
https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts

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

application/json
person_idstringrequired

Person ID to add as contact

is_primaryboolean

Set this person as the primary contact (default false)

notestring

Optional note for this contact relationship

Parameters

idstringrequiredpath

Job ID

Response

200OKobject

Contact added or already exists

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job or person not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Add contact to job
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(())
}
Request Body
{
  "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

PATCH
https://api.searchsoftware.nl/v4/records/jobs/{id}/contacts/{contact_id}

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

application/json
is_primaryboolean

Promote or demote this contact as primary (omit to leave unchanged)

notestring

Update the note for this contact relationship (omit to leave unchanged)

Parameters

idstringrequiredpath

Job ID

contact_idstringrequiredpath

Job contact record ID

Response

200OKobject

Contact updated

400Bad Requestobject

Invalid id, contact_id, or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job contact not found

422Unprocessable Entityobject

Update failed

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:write

apikey_authapiKey in query

API key in query string

Scopes: jobs:write

Update job contact
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates

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

idstringrequiredpath

Job ID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

includestringquery

Optional includes: person

Response

200OKobject

Job candidates list

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

List candidates for a job
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

GET
https://api.searchsoftware.nl/v4/records/jobs/{id}/candidates/{candidate_id}

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

idstringrequiredpath

Job ID

candidate_idstringrequiredpath

Job candidate record ID

includestringquery

Optional includes: person

Response

200OKobject

Job candidate

400Bad Requestobject

Invalid id or candidate_id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Job or candidate not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: jobs:read

apikey_authapiKey in query

API key in query string

Scopes: jobs:read

Get a single job candidate
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

GET
https://api.searchsoftware.nl/v4/sources

Lists all available sources. Requires sources:read.

Response

200OKobject

Sources list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: sources:read

apikey_authapiKey in query

API key in query string

Scopes: sources:read

List sources
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

GET
https://api.searchsoftware.nl/v4/workflows

Lists all workflow definitions in the workspace. Requires workflows:read.

Response

200OKobject

Workflows list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: workflows:read

apikey_authapiKey in query

API key in query string

Scopes: workflows:read

List workflows
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

GET
https://api.searchsoftware.nl/v4/workflows/phases

Lists all available workflow phases. Requires workflows:read.

Response

200OKobject

Workflow phases list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: workflows:read

apikey_authapiKey in query

API key in query string

Scopes: workflows:read

List workflow phases
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

GET
https://api.searchsoftware.nl/v4/workflows/stages

Lists all available workflow stages. Requires workflows:read.

Response

200OKobject

Workflow stages list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: workflows:read

apikey_authapiKey in query

API key in query string

Scopes: workflows:read

List workflow stages
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

GET
https://api.searchsoftware.nl/v4/users

Lists all users in the workspace. Requires users:read.

Response

200OKobject

Users list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: users:read

apikey_authapiKey in query

API key in query string

Scopes: users:read

List users
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

GET
https://api.searchsoftware.nl/v4/users/{id}

Fetches one user by ID. Requires users:read.

Parameters

idstringrequiredpath

User ID

Response

200OKobject

User found

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

User not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: users:read

apikey_authapiKey in query

API key in query string

Scopes: users:read

Get a user
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

GET
https://api.searchsoftware.nl/v4/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

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

includestringquery

Optional includes: method

owner_typestringquery

Owner record type: person, company, job, or job_contact

owner_idstringquery

Owner record ID (required when owner_type is set)

Response

200OKobject

Communications list

400Bad Requestobject

Invalid owner_id or mismatched owner_type/owner_id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: communications:read

apikey_authapiKey in query

API key in query string

Scopes: communications:read

List communications
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

POST
https://api.searchsoftware.nl/v4/communications

Creates a communication record and links it to an owner record. Requires communications:write.

Body

application/json
subjectstringrequired

Subject

summarystringrequired

Summary or body text

method_idstringrequired

Communication method ID

datestringrequired

The day the communication took place (YYYY-MM-DD). A datetime is still accepted for backward compatibility; its time component is discarded.

owner_typestringrequired

Owner record type: person, company, job, or job_contact

owner_idstringrequired

Owner record ID

created_bystring

User ID of the record creator

Response

200OKobject

Communication created

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Owner record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: communications:write

apikey_authapiKey in query

API key in query string

Scopes: communications:write

Create a communication
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/communication-methods

Returns all available communication methods, sorted alphabetically. Requires communications:read.

Response

200OKobject

Communication methods list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: communications:read

apikey_authapiKey in query

API key in query string

Scopes: communications:read

List communication methods
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

POST
https://api.searchsoftware.nl/v4/communication-methods

Creates a new communication method. Requires communications:write.

Body

application/json
namestringrequired

Method name (e.g. Phone, Email, LinkedIn)

Response

200OKobject

Communication method created

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: communications:write

apikey_authapiKey in query

API key in query string

Scopes: communications:write

Create a communication method
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/comments/for-todos

Returns every comment and image attached to each requested todo, oldest first. Requires both todos:read and comments:read.

Body

application/json
idsarrayrequired

Todo IDs to fetch comments for (max 100)

Response

200OKobject

Comments grouped by todo ID

400Bad Requestobject

Invalid todo ID or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Too many todo IDs

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: comments:read

apikey_authapiKey in query

API key in query string

Scopes: comments:read

List comments for todos
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/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

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

owner_typestringquery

Owner record type: person, company, job, or job_contact

owner_idstringquery

Owner record ID (required when owner_type is set)

Response

200OKobject

Comments list

400Bad Requestobject

Invalid owner_id or mismatched owner_type/owner_id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: comments:read

apikey_authapiKey in query

API key in query string

Scopes: comments:read

List comments
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

POST
https://api.searchsoftware.nl/v4/comments

Creates a comment and links it to an owner record. Requires comments:write.

Body

application/json
textstringrequired

Comment body text

owner_typestringrequired

Owner record type: person, company, job, or job_contact

owner_idstringrequired

Owner record ID

user_idstring

Optional user ID of the comment author

Response

200OKobject

Comment created

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Owner record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: comments:write

apikey_authapiKey in query

API key in query string

Scopes: comments:write

Create a comment
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/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

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

owner_typestringquery

Owner record type: person, company, job, or job_contact

owner_idstringquery

Owner record ID (required when owner_type is set)

Response

200OKobject

Notes list

400Bad Requestobject

Invalid owner_id or mismatched owner_type/owner_id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: notes:read

apikey_authapiKey in query

API key in query string

Scopes: notes:read

List notes
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

POST
https://api.searchsoftware.nl/v4/notes

Creates a note and links it to an owner record. Requires notes:write.

Body

application/json
titlestringrequired

Title

textstringrequired

Note body text

owner_typestringrequired

Owner record type: person, company, job, or job_contact

owner_idstringrequired

Owner record ID

created_bystring

User ID of the record creator

Response

200OKobject

Note created

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Owner record not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: notes:write

apikey_authapiKey in query

API key in query string

Scopes: notes:write

Create a note
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/work_history

Returns a paginated list of work history entries. Filter by person_id or company_id. Requires work_history:read.

Parameters

person_idstringquery

Filter by person SqID

company_idstringquery

Filter by company SqID

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Work history list

400Bad Requestobject

Invalid filter param

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: work_history:read

apikey_authapiKey in query

API key in query string

Scopes: work_history:read

List work history entries
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

POST
https://api.searchsoftware.nl/v4/work_history

Creates a new work history entry linking a person to a company. Requires work_history:write.

Body

application/json
person_idstringrequired

Person ID

company_idstring

Company ID

company_namestring

Company name if no linked company

work_titlestring

Job title

is_currentboolean

Current position flag

is_primary_contactboolean

Primary contact flag

Response

200OKobject

Work history entry created

400Bad Requestobject

Invalid body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Person or company not found

422Unprocessable Entityobject

Validation failed

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: work_history:write

apikey_authapiKey in query

API key in query string

Scopes: work_history:write

Create a work history entry
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/work_history/{id}

Returns a single work history entry by ID. Requires work_history:read.

Parameters

idstringrequiredpath

Work history entry ID

Response

200OKobject

Work history entry

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Entry not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: work_history:read

apikey_authapiKey in query

API key in query string

Scopes: work_history:read

Get a work history entry
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

DELETE
https://api.searchsoftware.nl/v4/work_history/{id}

Permanently deletes a work history entry. Requires work_history:write.

Parameters

idstringrequiredpath

Work history entry ID

Response

200OKobject

Work history entry deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Entry not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: work_history:write

apikey_authapiKey in query

API key in query string

Scopes: work_history:write

Delete a work history entry
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

PATCH
https://api.searchsoftware.nl/v4/work_history/{id}

Partially updates a work history entry. All body fields are optional. Requires work_history:write.

Body

application/json
company_idstring

Company ID

company_namestring

Company name if no linked company

work_titlestring

Job title

is_currentboolean

Current position flag

is_primary_contactboolean

Primary contact flag

Parameters

idstringrequiredpath

Work history entry ID

Response

200OKobject

Work history entry updated

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Entry or company not found

422Unprocessable Entityobject

Validation failed

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: work_history:write

apikey_authapiKey in query

API key in query string

Scopes: work_history:write

Update a work history entry
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/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

namestringquery

Exact group name to match (trimmed, case-insensitive)

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Category groups list

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:read

apikey_authapiKey in query

API key in query string

Scopes: categories:read

List category groups
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

POST
https://api.searchsoftware.nl/v4/category-groups

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

application/json
namestringrequired

Category group name

Response

200OKobject

Category group created or reused

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:write

apikey_authapiKey in query

API key in query string

Scopes: categories:write

Create a category group
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/category-groups/{id}

Returns a single category group by ID. Requires categories:read.

Parameters

idstringrequiredpath

Category group ID

Response

200OKobject

Category group

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Category group not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:read

apikey_authapiKey in query

API key in query string

Scopes: categories:read

Get a category group
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

DELETE
https://api.searchsoftware.nl/v4/category-groups/{id}

Permanently deletes a category group. Requires categories:write.

Parameters

idstringrequiredpath

Category group ID

Response

200OKobject

Category group deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Category group not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:write

apikey_authapiKey in query

API key in query string

Scopes: categories:write

Delete a category group
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

PATCH
https://api.searchsoftware.nl/v4/category-groups/{id}

Renames a category group. Requires categories:write.

Body

application/json
namestringrequired

New category group name

Parameters

idstringrequiredpath

Category group ID

Response

200OKobject

Category group updated

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Category group not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:write

apikey_authapiKey in query

API key in query string

Scopes: categories:write

Update a category group
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/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_idstringquery

Filter to a single category group by SqID

namestringquery

Exact category name to match (trimmed, case-insensitive)

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

Response

200OKobject

Categories list

400Bad Requestobject

Invalid group_id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:read

apikey_authapiKey in query

API key in query string

Scopes: categories:read

List categories
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

POST
https://api.searchsoftware.nl/v4/categories

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

application/json
namestringrequired

Category name

group_idstringrequired

Owning category group ID

Response

200OKobject

Category created or reused

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Category group not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:write

apikey_authapiKey in query

API key in query string

Scopes: categories:write

Create a category
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/categories/{id}

Returns a single category by ID. Requires categories:read.

Parameters

idstringrequiredpath

Category ID

Response

200OKobject

Category

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Category not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:read

apikey_authapiKey in query

API key in query string

Scopes: categories:read

Get a category
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

DELETE
https://api.searchsoftware.nl/v4/categories/{id}

Permanently deletes a category. Requires categories:write.

Parameters

idstringrequiredpath

Category ID

Response

200OKobject

Category deleted

400Bad Requestobject

Invalid id

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Category not found

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:write

apikey_authapiKey in query

API key in query string

Scopes: categories:write

Delete a category
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

PATCH
https://api.searchsoftware.nl/v4/categories/{id}

Renames a category. Requires categories:write.

Body

application/json
namestringrequired

New category name

Parameters

idstringrequiredpath

Category ID

Response

200OKobject

Category updated

400Bad Requestobject

Invalid id or body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Category not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: categories:write

apikey_authapiKey in query

API key in query string

Scopes: categories:write

Update a category
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/todos

List todos. Requires todos:read.

Parameters

limitstringquery

Max results, 1-100, default 25

offsetstringquery

Zero-based offset, default 0

owner_typestringquery

Owner type: person, company, job, or custom:

owner_idstringquery

Owner ID

assigned_tostringquery

Assigned user ID

list_idstringquery

Board list ID

statusstringquery

open, completed, or all

Response

200OKobject

List todos

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

List todos
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

POST
https://api.searchsoftware.nl/v4/todos

Create todo. Requires todos:write.

Body

application/json
textstringrequired
owner_typestring
owner_idstring
assigned_tostring
created_bystring
list_idstring
label_idsarray
is_priority_taskboolean
due_atstring

Response

200OKobject

Create todo

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Create todo
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(())
}
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"
}
{
  "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

POST
https://api.searchsoftware.nl/v4/todos/get-many

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

application/json
idsarrayrequired

Array of todo IDs to fetch (max 100)

Response

200OKobject

Todos

400Bad Requestobject

Invalid id in request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Too many ids or invalid request body

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

Get todos by IDs
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/todos/search

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

application/json
querystring

Search 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.

Show child attributes
opstringrequired
clausesArray<object>required
Show child attributes
fieldstringrequired
opstringrequired
valueany
sortArray<object>

Sort fields. Empty or omitted values default to created_at desc.

Show child attributes
fieldstringrequired
directionstringrequired

Response

200OKobject

Todo search results

400Bad Requestobject

Invalid request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

Search todos
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(())
}
Request Body
{
  "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
https://api.searchsoftware.nl/v4/todos/{id}

Get todo. Requires todos:read.

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Get todo

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

Get todo
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
https://api.searchsoftware.nl/v4/todos/{id}

Delete todo. Requires todos:write.

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Delete todo

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Delete todo
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

PATCH
https://api.searchsoftware.nl/v4/todos/{id}

Update todo. Requires todos:write.

Body

application/json
textstring
is_priority_taskboolean
due_atstring

RFC3339 datetime or null to clear

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Update todo

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Update todo
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/todos/{id}/complete

Complete todo. Requires todos:write.

Body

application/json
completed_bystring

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Complete todo

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Complete todo
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/todos/{id}/reopen

Reopen todo. Requires todos:write.

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Reopen todo

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Reopen todo
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

PUT
https://api.searchsoftware.nl/v4/todos/{id}/assignee

Assign or unassign todo user. Requires todos:write.

Body

application/json
user_idstring

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Assign or unassign todo user

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Assign or unassign todo user
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/todos/{id}/owner

Assign todo owner. Requires todos:write.

Body

application/json
owner_typestringrequired
owner_idstringrequired

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Assign todo owner

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Assign todo owner
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/todos/{id}/list

Move todo to board list. Requires todos:write.

Body

application/json
list_idstring

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Move todo to board list

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Move todo to board list
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/todos/boards

List todo boards. Requires todos:read.

Parameters

limitstringquery
offsetstringquery

Response

200OKobject

List todo boards

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

List todo boards
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

POST
https://api.searchsoftware.nl/v4/todos/boards

Create todo board. Requires todos:write.

Body

application/json
namestringrequired
created_bystring

Response

200OKobject

Create todo board

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Create todo board
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(())
}
Request Body
{
  "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
https://api.searchsoftware.nl/v4/todos/boards/{id}

Get todo board. Requires todos:read.

Parameters

idstringrequiredpath

Todo board ID

Response

200OKobject

Get todo board

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

Get todo board
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
https://api.searchsoftware.nl/v4/todos/boards/{id}

Delete todo board. Requires todos:write.

Parameters

idstringrequiredpath

Todo board ID

Response

200OKobject

Delete todo board

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Delete todo board
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

PATCH
https://api.searchsoftware.nl/v4/todos/boards/{id}

Update todo board. Requires todos:write.

Body

application/json
namestring

Parameters

idstringrequiredpath

Todo board ID

Response

200OKobject

Update todo board

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Update todo board
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/todos/boards/{id}/lists

List todo board lists. Requires todos:read.

Parameters

idstringrequiredpath

Todo board ID

Response

200OKobject

List todo board lists

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

List todo board lists
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

POST
https://api.searchsoftware.nl/v4/todos/boards/{id}/lists

Create todo board list. Requires todos:write.

Body

application/json
namestringrequired
text_colorstring
background_colorstring
created_bystring

Parameters

idstringrequiredpath

Todo board ID

Response

200OKobject

Create todo board list

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Create todo board list
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(())
}
Request Body
{
  "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
https://api.searchsoftware.nl/v4/todos/boards/lists/{id}

Get todo board list. Requires todos:read.

Parameters

idstringrequiredpath

Todo board list ID

Response

200OKobject

Get todo board list

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

Get todo board list
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
https://api.searchsoftware.nl/v4/todos/boards/lists/{id}

Delete todo board list. Requires todos:write.

Parameters

idstringrequiredpath

Todo board list ID

Response

200OKobject

Delete todo board list

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Delete todo board list
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

PATCH
https://api.searchsoftware.nl/v4/todos/boards/lists/{id}

Update todo board list. Requires todos:write.

Body

application/json
namestring
text_colorstring
background_colorstring

Parameters

idstringrequiredpath

Todo board list ID

Response

200OKobject

Update todo board list

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Update todo board list
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/todos/labels

List todo labels. Requires todos:read.

Parameters

namestringquery
limitstringquery
offsetstringquery

Response

200OKobject

List todo labels

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

List todo labels
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

POST
https://api.searchsoftware.nl/v4/todos/labels

Create todo label. Requires todos:write.

Body

application/json
namestringrequired
text_colorstring
background_colorstring
created_bystring

Response

200OKobject

Create todo label

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Create todo label
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(())
}
Request Body
{
  "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
https://api.searchsoftware.nl/v4/todos/labels/{id}

Get todo label. Requires todos:read.

Parameters

idstringrequiredpath

Todo label ID

Response

200OKobject

Get todo label

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

Get todo label
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
https://api.searchsoftware.nl/v4/todos/labels/{id}

Delete todo label. Requires todos:write.

Parameters

idstringrequiredpath

Todo label ID

Response

200OKobject

Delete todo label

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Delete todo label
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

PATCH
https://api.searchsoftware.nl/v4/todos/labels/{id}

Update todo label. Requires todos:write.

Body

application/json
namestring
text_colorstring
background_colorstring

Parameters

idstringrequiredpath

Todo label ID

Response

200OKobject

Update todo label

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Update todo label
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(())
}
Request Body
{
  "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

GET
https://api.searchsoftware.nl/v4/todos/{id}/labels

List labels for todo. Requires todos:read.

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

List labels for todo

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:read

apikey_authapiKey in query

API key in query string

Scopes: todos:read

List labels for todo
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

POST
https://api.searchsoftware.nl/v4/todos/{id}/labels

Add todo label. Requires todos:write.

Body

application/json
label_idstringrequired

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Add todo label

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Add todo label
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(())
}
Request Body
{
  "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

PUT
https://api.searchsoftware.nl/v4/todos/{id}/labels

Set todo labels. Requires todos:write.

Body

application/json
label_idsarrayrequired

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Set todo labels

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Set todo labels
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(())
}
Request Body
{
  "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

DELETE
https://api.searchsoftware.nl/v4/todos/{id}/labels/{label_id}

Remove todo label. Requires todos:write.

Parameters

idstringrequiredpath

Todo ID

label_idstringrequiredpath

Todo label ID

Response

200OKobject

Remove todo label

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Remove todo label
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

POST
https://api.searchsoftware.nl/v4/todos/{id}/checklist

Create a todo checklist task. Requires todos:write.

Body

application/json
textstringrequired
created_bystring

Parameters

idstringrequiredpath

Todo ID

Response

200OKobject

Create a todo checklist task

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Create a todo checklist task
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/complete

Complete a todo checklist task. Requires todos:write.

Body

application/json
completed_bystring

Parameters

idstringrequiredpath

Todo ID

task_idstringrequiredpath

Checklist task ID

Response

200OKobject

Complete a todo checklist task

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Complete a todo checklist task
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(())
}
Request Body
{
  "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

POST
https://api.searchsoftware.nl/v4/todos/{id}/checklist/{task_id}/reopen

Reopen a todo checklist task. Requires todos:write.

Parameters

idstringrequiredpath

Todo ID

task_idstringrequiredpath

Checklist task ID

Response

200OKobject

Reopen a todo checklist task

400Bad Requestobject

Invalid id or request body

401Unauthorizedobject

Invalid API key

403Forbiddenobject

Insufficient scope

404Not Foundobject

Resource not found

422Unprocessable Entityobject

Validation error

500Internal Server Errorobject

Internal server error

Authorization

bearer_authhttp (bearer) in header

API key in Authorization header

Scopes: todos:write

apikey_authapiKey in query

API key in query string

Scopes: todos:write

Reopen a todo checklist task
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

object
addressstring<email>
is_primaryboolean
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "address": "jane@example.com",
  "is_primary": true,
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

PrimaryEmailInclude

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
addressstring<email>
is_primaryboolean
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
numberstring
is_primaryboolean
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "number": "+31612345678",
  "is_primary": true,
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

PrimaryPhoneInclude

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
numberstring
is_primaryboolean
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
formattedstring
is_primaryboolean
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
formattedstring
is_primaryboolean
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
namestring
url_idstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "name": "LinkedIn",
  "url_id": "linkedin",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

SourceInclude

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring
url_idstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object

Workflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.

phase_status_idstring | null

Identifier

created_bystring | null

Identifier

last_status_changed_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Workflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.

Show child attributes
phase_status_idstring | null

Identifier

created_bystring | null

Identifier

last_status_changed_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Workflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.

Show child attributes
phase_status_idstring | null

Identifier

created_bystring | null

Identifier

last_status_changed_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Workflow flow status. phase_status_id references the workflow-phase objects from the workflows endpoints.

Show child attributes
phase_status_idstring | null

Identifier

created_bystring | null

Identifier

last_status_changed_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
namestring
image_urlstring<uri> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "name": "Acme AB",
  "image_url": "https://example.com",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

CompanyInclude

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring
image_urlstring<uri> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

[key: string]stringplainmarkdownhtml
Example
{}

RecordValues

object

Optional 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
Example
{}

UpdateRecordRequest

object
namestring

New record name. For jobs this updates the title.

custom_fieldsobject

Custom field values keyed by field slug. JSON null clears the value; arrays and objects are accepted for multi-value fields.

Show child attributes
[key: string]any
Example
{
  "name": "Jane Doe",
  "custom_fields": {}
}

PersonAttributes

object

Base 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.

namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
current_companystring | null

Current employer name derived from the current work-history entry.

current_positionstring | null

Current work title derived from the current work-history entry.

assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

genderstring | null
birthdatestring<date> | null

Date of birth as a calendar day (YYYY-MM-DD). Null when the person has no birthdate on file.

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
relevant_career_experience_start_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
Example
{
  "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

object
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
current_companystring | null

Current employer name derived from the current work-history entry.

current_positionstring | null

Current work title derived from the current work-history entry.

assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

genderstring | null
birthdatestring<date> | null

Date of birth as a calendar day (YYYY-MM-DD). Null when the person has no birthdate on file.

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
relevant_career_experience_start_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
current_companystring | null

Current employer name derived from the current work-history entry.

current_positionstring | null

Current work title derived from the current work-history entry.

assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

genderstring | null
birthdatestring<date> | null

Date of birth as a calendar day (YYYY-MM-DD). Null when the person has no birthdate on file.

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
relevant_career_experience_start_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
current_companystring | null

Current employer name derived from the current work-history entry.

current_positionstring | null

Current work title derived from the current work-history entry.

assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

genderstring | null
birthdatestring<date> | null

Date of birth as a calendar day (YYYY-MM-DD). Null when the person has no birthdate on file.

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
relevant_career_experience_start_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
current_companystring | null

Current employer name derived from the current work-history entry.

current_positionstring | null

Current work title derived from the current work-history entry.

assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

genderstring | null
birthdatestring<date> | null

Date of birth as a calendar day (YYYY-MM-DD). Null when the person has no birthdate on file.

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
relevant_career_experience_start_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
current_companystring | null

Current employer name derived from the current work-history entry.

current_positionstring | null

Current work title derived from the current work-history entry.

assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

genderstring | null
birthdatestring<date> | null

Date of birth as a calendar day (YYYY-MM-DD). Null when the person has no birthdate on file.

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
relevant_career_experience_start_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object

Base 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.

namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
active_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 | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
Example
{
  "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

object
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
active_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 | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
active_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 | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
active_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 | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
active_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 | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_emailobject | null
primary_phoneobject | null
primary_locationobject | null
sourceobject | null
flowobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
created_atstring<date-time>
updated_atstring<date-time>
email_addressstring<email> | null
phone_numberstring | null
addressstring | null
active_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 | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

workflow_phase_statusstring | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object

Base 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.

namestring
company_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
addressstring | null
assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

candidate_workflow_idstring | null

Identifier

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 | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
Example
{
  "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

object
primary_locationobject | null
sourceobject | null
flowobject | null
companyobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
company_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
addressstring | null
assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

candidate_workflow_idstring | null

Identifier

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 | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_locationobject | null
sourceobject | null
flowobject | null
companyobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
company_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
addressstring | null
assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

candidate_workflow_idstring | null

Identifier

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 | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
company_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
addressstring | null
assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

candidate_workflow_idstring | null

Identifier

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 | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_locationobject | null
sourceobject | null
flowobject | null
companyobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
company_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
addressstring | null
assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

candidate_workflow_idstring | null

Identifier

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 | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
objectsobjectrequired
Show child attributes
primary_locationobject | null
sourceobject | null
flowobject | null
companyobject | null
notesArray<object>

Included notes array (newest-first, max 25). Empty array when no notes.

Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
typestring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
valuesobject

Optional 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.

Show child attributes
[key: string]any
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired

Base 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.

Show child attributes
namestring
company_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
addressstring | null
assigned_tostring | null

Identifier

assigned_atstring<date-time> | null
assigned_bystring | null

Identifier

created_bystring | null

Identifier

image_idstring | null

Identifier

primary_document_idstring | null

Identifier

image_urlstring<uri> | null
profile_urlstring<uri> | null

Absolute profile link. Pikaflow uses an opaque record ID; SearchSoftware uses the numeric record ID.

statusstring
status_changed_atstring<date-time> | null
workflow_idstring | null

Identifier

candidate_workflow_idstring | null

Identifier

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 | null

Name of the workflow phase the record is currently in. Null when the record is not in a workflow phase.

workflow_stage_statusstring | null

Name 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> | null

When 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>
custom_field_formatsobjectrequired

Text custom-field render formats keyed by field slug. Values are plain, markdown, or html.

Show child attributes
[key: string]stringplainmarkdownhtml
Example
{
  "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

object
parent_source_idstring | null

Identifier

namestring
descriptionstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "parent_source_id": "vM7Lp2q",
  "name": "LinkedIn",
  "description": "string",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

SourceData

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
parent_source_idstring | null

Identifier

namestring
descriptionstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
parent_source_idstring | null

Identifier

namestring
descriptionstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
namestring | null
color_bgstring | null
color_textstring | null
is_archivedboolean
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
color_bgstring | null
color_textstring | null
is_archivedboolean
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
color_bgstring | null
color_textstring | null
is_archivedboolean
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
color_bgstring | null
color_textstring | null
is_archivedboolean
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
namestring | null
full_namestring | null
emailstring | null
email_verified_atstring<date-time> | null
phonestring | null
activeboolean
image_idstring | null

Identifier

image_urlstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
full_namestring | null
emailstring | null
email_verified_atstring<date-time> | null
phonestring | null
activeboolean
image_idstring | null

Identifier

image_urlstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
full_namestring | null
emailstring | null
email_verified_atstring<date-time> | null
phonestring | null
activeboolean
image_idstring | null

Identifier

image_urlstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
full_namestring | null
emailstring | null
email_verified_atstring<date-time> | null
phonestring | null
activeboolean
image_idstring | null

Identifier

image_urlstring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
workflow_idstring | null

Identifier

stage_idstring | null

Identifier

statusstring
orderinteger<int32>
colorstring
hide_contentboolean
is_finalboolean
available_in_draft_listboolean
max_daysinteger<int32> | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
workflow_idstring | null

Identifier

stage_idstring | null

Identifier

statusstring
orderinteger<int32>
colorstring
hide_contentboolean
is_finalboolean
available_in_draft_listboolean
max_daysinteger<int32> | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
workflow_idstring | null

Identifier

stage_idstring | null

Identifier

statusstring
orderinteger<int32>
colorstring
hide_contentboolean
is_finalboolean
available_in_draft_listboolean
max_daysinteger<int32> | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
workflow_idstring | null

Identifier

statusstring
orderinteger<int32>
colorstring | null
color_bgstring | null
color_textstring | null
completion_expected_percentageinteger<int32> | null
max_daysinteger<int32> | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
workflow_idstring | null

Identifier

statusstring
orderinteger<int32>
colorstring | null
color_bgstring | null
color_textstring | null
completion_expected_percentageinteger<int32> | null
max_daysinteger<int32> | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
workflow_idstring | null

Identifier

statusstring
orderinteger<int32>
colorstring | null
color_bgstring | null
color_textstring | null
completion_expected_percentageinteger<int32> | null
max_daysinteger<int32> | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
namestring | null
for_item_typestring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "name": "Hiring Pipeline",
  "for_item_type": "job_candidate",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

WorkflowData

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
for_item_typestring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring | null
for_item_typestring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
item_typestringrequired
item_idstringrequired

Identifier

source_idstringrequired

Identifier

Example
{
  "item_type": "person",
  "item_id": "vM7Lp2q",
  "source_id": "vM7Lp2q"
}

SetSourceResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
item_typestringrequired
item_idstringrequired

Identifier

source_idstringrequired

Identifier

Example
{
  "status": "ok",
  "data": {
    "item_type": "person",
    "item_id": "vM7Lp2q",
    "source_id": "vM7Lp2q"
  }
}

SetWorkflowPhaseData

object
item_typestringrequired
item_idstringrequired

Identifier

person_idstring | null

Identifier

workflow_idstringrequired

Identifier

phase_status_idstringrequired

Identifier

log_idstring | null

Identifier

Example
{
  "item_type": "person",
  "item_id": "vM7Lp2q",
  "person_id": "vM7Lp2q",
  "workflow_id": "vM7Lp2q",
  "phase_status_id": "vM7Lp2q",
  "log_id": "vM7Lp2q"
}

SetWorkflowPhaseResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
item_typestringrequired
item_idstringrequired

Identifier

person_idstring | null

Identifier

workflow_idstringrequired

Identifier

phase_status_idstringrequired

Identifier

log_idstring | null

Identifier

Example
{
  "status": "ok",
  "data": {
    "item_type": "person",
    "item_id": "vM7Lp2q",
    "person_id": "vM7Lp2q",
    "workflow_id": "vM7Lp2q",
    "phase_status_id": "vM7Lp2q",
    "log_id": "vM7Lp2q"
  }
}

AddJobContactData

object
idstringrequired

Identifier

job_idstringrequired

Identifier

person_idstringrequired

Identifier

is_primarybooleanrequired
notestring | null
Example
{
  "id": "vM7Lp2q",
  "job_id": "vM7Lp2q",
  "person_id": "vM7Lp2q",
  "is_primary": false,
  "note": "string"
}

JobContactAttributes

object
person_idstring | null

Identifier

is_primaryboolean
notestring | null
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "person_id": "vM7Lp2q",
  "is_primary": false,
  "note": "string",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

JobContactPersonObject

object
idstring

Identifier

namestring | null
image_urlstring | null
Example
{
  "id": "vM7Lp2q",
  "name": "string",
  "image_url": "string"
}

JobContactObjects

object
personobject | null
Example
{
  "person": {
    "id": "vM7Lp2q",
    "name": "string",
    "image_url": "string"
  }
}

JobContactData

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

is_primaryboolean
notestring | null
created_atstring<date-time>
updated_atstring<date-time>
objectsobject
Show child attributes
personobject | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

is_primaryboolean
notestring | null
created_atstring<date-time>
updated_atstring<date-time>
objectsobject
Show child attributes
personobject | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

job_idstringrequired

Identifier

person_idstringrequired

Identifier

is_primarybooleanrequired
notestring | null
Example
{
  "status": "ok",
  "data": {
    "id": "vM7Lp2q",
    "job_id": "vM7Lp2q",
    "person_id": "vM7Lp2q",
    "is_primary": false,
    "note": "string"
  }
}

UpdateJobContactResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

job_idstringrequired

Identifier

person_idstringrequired

Identifier

is_primarybooleanrequired
notestring | null
Example
{
  "status": "ok",
  "data": {
    "id": "vM7Lp2q",
    "job_id": "vM7Lp2q",
    "person_id": "vM7Lp2q",
    "is_primary": false,
    "note": "string"
  }
}

JobCandidatePersonObject

object
idstring

Identifier

namestring | null
image_urlstring | null
email_addressstring | null
Example
{
  "id": "vM7Lp2q",
  "name": "string",
  "image_url": "string",
  "email_address": "string"
}

JobCandidateObjects

object
personobject | null
Example
{
  "person": {
    "id": "vM7Lp2q",
    "name": "string",
    "image_url": "string",
    "email_address": "string"
  }
}

JobCandidateAttributes

object
person_idstring | null

Identifier

status_idstring | null

Identifier

rankinginteger<int32> | null

Candidate ranking

created_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
last_status_changed_bystring | null

Identifier

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

status_idstring | null

Identifier

rankinginteger<int32> | null

Candidate ranking

created_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
last_status_changed_bystring | null

Identifier

created_atstring<date-time>required
updated_atstring<date-time>required
objectsobject
Show child attributes
personobject | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

status_idstring | null

Identifier

rankinginteger<int32> | null

Candidate ranking

created_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
last_status_changed_bystring | null

Identifier

created_atstring<date-time>required
updated_atstring<date-time>required
objectsobject
Show child attributes
personobject | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

status_idstring | null

Identifier

rankinginteger<int32> | null

Candidate ranking

created_bystring | null

Identifier

last_status_changed_atstring<date-time> | null
last_status_changed_bystring | null

Identifier

created_atstring<date-time>required
updated_atstring<date-time>required
objectsobject
Show child attributes
personobject | null
Example
{
  "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

object
idstringrequired

Identifier

filenamestringrequired
mimestringrequired
sizeinteger<int32>required

File size in bytes

Example
{
  "id": "vM7Lp2q",
  "filename": "cv_john_doe.pdf",
  "mime": "application/pdf",
  "size": 102400
}

UploadFileResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

filenamestringrequired
mimestringrequired
sizeinteger<int32>required

File size in bytes

Example
{
  "status": "ok",
  "data": {
    "id": "vM7Lp2q",
    "filename": "cv_john_doe.pdf",
    "mime": "application/pdf",
    "size": 102400
  }
}

UploadImageData

object
idstringrequired

Identifier

filenamestringrequired
mimestringrequired
sizeinteger<int32>required

Image size in bytes

Example
{
  "id": "vM7Lp2q",
  "filename": "headshot.jpg",
  "mime": "image/jpeg",
  "size": 204800
}

UploadImageResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

filenamestringrequired
mimestringrequired
sizeinteger<int32>required

Image size in bytes

Example
{
  "status": "ok",
  "data": {
    "id": "vM7Lp2q",
    "filename": "headshot.jpg",
    "mime": "image/jpeg",
    "size": 204800
  }
}

AliasAttributes

object
aliasstringrequired

Alias text

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "alias": "ACME Corp",
  "created_at": "2026-01-15T09:00:00Z",
  "updated_at": "2026-01-15T09:00:00Z"
}

AliasObject

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
aliasstringrequired

Alias text

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "id": "vM7Lp2q",
  "type": "alias",
  "attributes": {
    "alias": "ACME Corp",
    "created_at": "2026-01-15T09:00:00Z",
    "updated_at": "2026-01-15T09:00:00Z"
  }
}

AliasResponse

object
statusstringrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
aliasstringrequired

Alias text

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
statusstringrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
aliasstringrequired

Alias text

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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"
      }
    }
  ]
}

CreateAliasRequest

object
aliasstringrequired

Alias text

Example
{
  "alias": "ACME Corp"
}

DeleteAliasResponse

object
statusstringrequired
dataobjectrequired
Show child attributes
deletedbooleanrequired
alias_idstringrequired

Identifier

Example
{
  "status": "ok",
  "data": {
    "deleted": true,
    "alias_id": "vM7Lp2q"
  }
}

BookmarkAttributes

object
urlstringrequired

Bookmark URL

titlestring | null

Bookmark title

commentstring | null

Optional comment

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "url": "https://example.com",
  "title": "Example site",
  "comment": "string",
  "created_at": "2026-01-15T09:00:00Z",
  "updated_at": "2026-01-15T09:00:00Z"
}

BookmarkObject

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
urlstringrequired

Bookmark URL

titlestring | null

Bookmark title

commentstring | null

Optional comment

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
statusstringrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
urlstringrequired

Bookmark URL

titlestring | null

Bookmark title

commentstring | null

Optional comment

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
statusstringrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
urlstringrequired

Bookmark URL

titlestring | null

Bookmark title

commentstring | null

Optional comment

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
urlstringrequired

Bookmark URL

titlestring | null

Bookmark title

commentstring | null

Optional comment

Example
{
  "url": "https://example.com",
  "title": "Example site",
  "comment": "string"
}

DeleteBookmarkResponse

object
statusstringrequired
dataobjectrequired
Show child attributes
deletedbooleanrequired
bookmark_idstringrequired

Identifier

Example
{
  "status": "ok",
  "data": {
    "deleted": true,
    "bookmark_id": "vM7Lp2q"
  }
}

FileItem

object
idstring

Identifier

typestringfile
attributesobject
Show child attributes
namestring | null
filenamestring | null
mimestring | null
sizeinteger<int32> | null

Size in bytes

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstring

Identifier

typestringfile
attributesobject
Show child attributes
namestring | null
filenamestring | null
mimestring | null
sizeinteger<int32> | null

Size in bytes

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstring

Identifier

typestringimage
attributesobject
Show child attributes
namestring | null
filenamestring | null
mimestring | null
sizeinteger<int32> | null

Size in bytes

widthinteger<int32> | null
heightinteger<int32> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstring

Identifier

typestringimage
attributesobject
Show child attributes
namestring | null
filenamestring | null
mimestring | null
sizeinteger<int32> | null

Size in bytes

widthinteger<int32> | null
heightinteger<int32> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
subjectstring | null
summarystring | null
method_idstring | null

Identifier

datestring<date> | null

The day the communication took place (YYYY-MM-DD). Null when unset.

created_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

namestring | nullrequired
Example
{
  "id": "vM7Lp2q",
  "name": "Phone"
}

CommunicationObjects

object
methodobject | null
Example
{
  "method": {
    "id": "vM7Lp2q",
    "name": "Phone"
  }
}

CommunicationData

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
subjectstring | null
summarystring | null
method_idstring | null

Identifier

datestring<date> | null

The day the communication took place (YYYY-MM-DD). Null when unset.

created_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
objectsobject
Show child attributes
methodobject | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
subjectstring | null
summarystring | null
method_idstring | null

Identifier

datestring<date> | null

The day the communication took place (YYYY-MM-DD). Null when unset.

created_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
objectsobject
Show child attributes
methodobject | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
subjectstring | null
summarystring | null
method_idstring | null

Identifier

datestring<date> | null

The day the communication took place (YYYY-MM-DD). Null when unset.

created_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
objectsobject
Show child attributes
methodobject | null
Example
{
  "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

object
namestring | nullrequired
emailstring<email> | nullrequired
Example
{
  "name": "Jane",
  "email": "jane@example.com"
}

EmailAttachment

object
idstringrequired

Identifier

namestring | nullrequired
file_namestring | nullrequired
mimestring | nullrequired
sizeinteger<int32> | nullrequired
created_atstring<date-time> | nullrequired
Example
{
  "id": "vM7Lp2q",
  "name": "cv.pdf",
  "file_name": "cv.pdf",
  "mime": "application/pdf",
  "size": 12345,
  "created_at": "2026-03-10T14:30:00Z"
}

EmailAttributes

object
subjectstring | null
textstring | null
htmlstring | null
toArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
fromArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
ccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
bccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
labelsArray<string>
message_idstring | null
user_idstring | null

Identifier

is_privateboolean
is_readboolean
is_archivedboolean
sent_atstring<date-time> | null
attachmentsArray<object>
Show child attributes
idstringrequired

Identifier

namestring | nullrequired
file_namestring | nullrequired
mimestring | nullrequired
sizeinteger<int32> | nullrequired
created_atstring<date-time> | nullrequired
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
subjectstring | null
textstring | null
htmlstring | null
toArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
fromArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
ccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
bccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
labelsArray<string>
message_idstring | null
user_idstring | null

Identifier

is_privateboolean
is_readboolean
is_archivedboolean
sent_atstring<date-time> | null
attachmentsArray<object>
Show child attributes
idstringrequired

Identifier

namestring | nullrequired
file_namestring | nullrequired
mimestring | nullrequired
sizeinteger<int32> | nullrequired
created_atstring<date-time> | nullrequired
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
subjectstring | null
textstring | null
htmlstring | null
toArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
fromArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
ccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
bccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
labelsArray<string>
message_idstring | null
user_idstring | null

Identifier

is_privateboolean
is_readboolean
is_archivedboolean
sent_atstring<date-time> | null
attachmentsArray<object>
Show child attributes
idstringrequired

Identifier

namestring | nullrequired
file_namestring | nullrequired
mimestring | nullrequired
sizeinteger<int32> | nullrequired
created_atstring<date-time> | nullrequired
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
subjectstring | null
textstring | null
htmlstring | null
toArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
fromArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
ccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
bccArray<object>
Show child attributes
namestring | nullrequired
emailstring<email> | nullrequired
labelsArray<string>
message_idstring | null
user_idstring | null

Identifier

is_privateboolean
is_readboolean
is_archivedboolean
sent_atstring<date-time> | null
attachmentsArray<object>
Show child attributes
idstringrequired

Identifier

namestring | nullrequired
file_namestring | nullrequired
mimestring | nullrequired
sizeinteger<int32> | nullrequired
created_atstring<date-time> | nullrequired
Example
{
  "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

object
textstring | null
user_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "text": "Great candidate!",
  "user_id": "vM7Lp2q",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

CommentData

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
textstring | null
user_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

image_urlstring<uri>required
full_image_urlstring<uri>required
namestringrequired
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
textstring | null
user_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
imagesArray<object>required
Show child attributes
idstringrequired

Identifier

image_urlstring<uri>required
full_image_urlstring<uri>required
namestringrequired
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
[key: string]Array<object>
Example
{
  "status": "ok",
  "data": {}
}

CommentsListResponse

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
textstring | null
user_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
textstring | null
user_idstring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
titlestring | null
textstring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
titlestring | null
textstring | null
created_bystring | null

Identifier

last_edited_bystring | null

Identifier

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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"
    }
  }
}

CommunicationMethodAttributes

object
namestring
Example
{
  "name": "Phone"
}

CommunicationMethodData

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring
Example
{
  "id": "vM7Lp2q",
  "type": "communication_method",
  "attributes": {
    "name": "Phone"
  }
}

CommunicationMethodsListResponse

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring
Example
{
  "status": "ok",
  "data": [
    {
      "id": "vM7Lp2q",
      "type": "communication_method",
      "attributes": {
        "name": "Phone"
      }
    }
  ]
}

CommunicationMethodResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
namestring
Example
{
  "status": "ok",
  "data": {
    "id": "vM7Lp2q",
    "type": "communication_method",
    "attributes": {
      "name": "Phone"
    }
  }
}

WorkHistoryAttributes

object
person_idstring | null

Identifier

company_idstring | null

Identifier

company_namestring | null

Company name (free text if no company linked)

work_titlestring | null

Job title at this position

is_currentbooleanrequired

Whether this is the current position

is_primary_contactbooleanrequired

Whether this is the primary contact role

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

company_idstring | null

Identifier

company_namestring | null

Company name (free text if no company linked)

work_titlestring | null

Job title at this position

is_currentbooleanrequired

Whether this is the current position

is_primary_contactbooleanrequired

Whether this is the primary contact role

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
statusstringrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

company_idstring | null

Identifier

company_namestring | null

Company name (free text if no company linked)

work_titlestring | null

Job title at this position

is_currentbooleanrequired

Whether this is the current position

is_primary_contactbooleanrequired

Whether this is the primary contact role

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
statusstringrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringrequired
attributesobjectrequired
Show child attributes
person_idstring | null

Identifier

company_idstring | null

Identifier

company_namestring | null

Company name (free text if no company linked)

work_titlestring | null

Job title at this position

is_currentbooleanrequired

Whether this is the current position

is_primary_contactbooleanrequired

Whether this is the primary contact role

created_atstring<date-time>required
updated_atstring<date-time>required
Example
{
  "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

object
person_idstringrequired

Identifier

company_idstring | null

Identifier

company_namestring | null

Company name if no linked company

work_titlestring | null

Job title

is_currentboolean | null

Current position flag

is_primary_contactboolean | null

Primary contact flag

Example
{
  "person_id": "vM7Lp2q",
  "company_id": "vM7Lp2q",
  "company_name": "string",
  "work_title": "string",
  "is_current": true,
  "is_primary_contact": true
}

UpdateWorkHistoryRequest

object
company_idstring | null

Identifier

company_namestring | null

Company name if no linked company

work_titlestring | null

Job title

is_currentboolean | null

Current position flag

is_primary_contactboolean | null

Primary contact flag

Example
{
  "company_id": "vM7Lp2q",
  "company_name": "string",
  "work_title": "string",
  "is_current": true,
  "is_primary_contact": true
}

DeleteWorkHistoryResponse

object
statusstringrequired
dataobjectrequired
Show child attributes
deletedbooleanrequired
idstringrequired

Identifier

Example
{
  "status": "ok",
  "data": {
    "deleted": true,
    "id": "vM7Lp2q"
  }
}

CategoryGroupAttributes

object
namestring | nullrequired
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "name": "utm_source",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

CategoryGroupObject

object
idstringrequired

Identifier

typestringcategory_grouprequired
attributesobjectrequired
Show child attributes
namestring | nullrequired
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "id": "vM7Lp2q",
  "type": "category_group",
  "attributes": {
    "name": "utm_source",
    "created_at": "2026-03-10T14:30:00Z",
    "updated_at": "2026-03-10T14:30:00Z"
  }
}

CategoryGroupResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringcategory_grouprequired
attributesobjectrequired
Show child attributes
namestring | nullrequired
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringcategory_grouprequired
attributesobjectrequired
Show child attributes
namestring | nullrequired
created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
namestringrequired

Category group name

Example
{
  "name": "utm_source"
}

UpdateCategoryGroupRequest

object
namestringrequired

New category group name

Example
{
  "name": "utm_source"
}

CategoryAttributes

object
namestring | nullrequired
group_idstringrequired

Owning category group ID

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "name": "newsletter",
  "group_id": "vM7Lp2q",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

CategoryObject

object
idstringrequired

Identifier

typestringcategoryrequired
attributesobjectrequired
Show child attributes
namestring | nullrequired
group_idstringrequired

Owning category group ID

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringcategoryrequired
attributesobjectrequired
Show child attributes
namestring | nullrequired
group_idstringrequired

Owning category group ID

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringcategoryrequired
attributesobjectrequired
Show child attributes
namestring | nullrequired
group_idstringrequired

Owning category group ID

created_atstring<date-time>
updated_atstring<date-time>
Example
{
  "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

object
namestringrequired

Category name

group_idstringrequired

Owning category group ID

Example
{
  "name": "newsletter",
  "group_id": "vM7Lp2q"
}

UpdateCategoryRequest

object
namestringrequired

New category name

Example
{
  "name": "newsletter"
}

AddCategoryRequest

object
category_idstringrequired

Category ID to link to the record

Example
{
  "category_id": "vM7Lp2q"
}

DeleteCategoryLinkResponse

object
statusstringokrequired
dataobjectrequired
Show child attributes
deletedbooleanrequired
category_idstringrequired

Identifier

Example
{
  "status": "ok",
  "data": {
    "deleted": true,
    "category_id": "vM7Lp2q"
  }
}

TodoAttributes

object
textstring | null
owner_typestring | null
owner_idstring | null

Identifier

assigned_tostring | null

Identifier

created_bystring | null

Identifier

completed_bystring | null

Identifier

list_idstring | null

Identifier

label_idsArray<string>
is_priority_taskboolean
due_atstring<date-time> | null
completed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstringrequired

Identifier

typestringtodorequired
attributesobjectrequired
Show child attributes
textstring | null
owner_typestring | null
owner_idstring | null

Identifier

assigned_tostring | null

Identifier

created_bystring | null

Identifier

completed_bystring | null

Identifier

list_idstring | null

Identifier

label_idsArray<string>
is_priority_taskboolean
due_atstring<date-time> | null
completed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringtodorequired
attributesobjectrequired
Show child attributes
textstring | null
owner_typestring | null
owner_idstring | null

Identifier

assigned_tostring | null

Identifier

created_bystring | null

Identifier

completed_bystring | null

Identifier

list_idstring | null

Identifier

label_idsArray<string>
is_priority_taskboolean
due_atstring<date-time> | null
completed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringtodorequired
attributesobjectrequired
Show child attributes
textstring | null
owner_typestring | null
owner_idstring | null

Identifier

assigned_tostring | null

Identifier

created_bystring | null

Identifier

completed_bystring | null

Identifier

list_idstring | null

Identifier

label_idsArray<string>
is_priority_taskboolean
due_atstring<date-time> | null
completed_atstring<date-time> | null
created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
namestring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "name": "Recruiting",
  "created_by": "vM7Lp2q",
  "created_at": "2026-03-10T14:30:00Z",
  "updated_at": "2026-03-10T14:30:00Z"
}

TodoBoardObject

object
idstringrequired

Identifier

typestringtodo_boardrequired
attributesobjectrequired
Show child attributes
namestring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringtodo_boardrequired
attributesobjectrequired
Show child attributes
namestring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringtodo_boardrequired
attributesobjectrequired
Show child attributes
namestring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
board_idstring | null

Identifier

namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstringrequired

Identifier

typestringtodo_board_listrequired
attributesobjectrequired
Show child attributes
board_idstring | null

Identifier

namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringtodo_board_listrequired
attributesobjectrequired
Show child attributes
board_idstring | null

Identifier

namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringtodo_board_listrequired
attributesobjectrequired
Show child attributes
board_idstring | null

Identifier

namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
idstringrequired

Identifier

typestringtodo_labelrequired
attributesobjectrequired
Show child attributes
namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataobjectrequired
Show child attributes
idstringrequired

Identifier

typestringtodo_labelrequired
attributesobjectrequired
Show child attributes
namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
statusstringokrequired
dataArray<object>required
Show child attributes
idstringrequired

Identifier

typestringtodo_labelrequired
attributesobjectrequired
Show child attributes
namestring | null
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

created_atstring<date-time> | null
updated_atstring<date-time> | null
Example
{
  "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

object
textstringrequired
owner_typestring | null
owner_idstring | null

Identifier

assigned_tostring | null

Identifier

created_bystring | null

Identifier

list_idstring | null

Identifier

label_idsArray<string>
is_priority_taskboolean | null
due_atstring<date-time> | null
Example
{
  "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

object
textstring | null
is_priority_taskboolean | null
due_atstring<date-time> | null
Example
{
  "text": "string",
  "is_priority_task": true,
  "due_at": "2026-03-10T14:30:00Z"
}

CompleteTodoRequest

object
completed_bystring | null

Identifier

Example
{
  "completed_by": "vM7Lp2q"
}

AssignTodoUserRequest

object
user_idstring | null

Identifier

Example
{
  "user_id": "vM7Lp2q"
}

AssignTodoOwnerRequest

object
owner_typestringrequired
owner_idstringrequired

Identifier

Example
{
  "owner_type": "string",
  "owner_id": "vM7Lp2q"
}

MoveTodoToBoardListRequest

object
list_idstring | null

Identifier

Example
{
  "list_id": "vM7Lp2q"
}

SetTodoLabelsRequest

object
label_idsArray<string>required
Example
{
  "label_ids": [
    "vM7Lp2q"
  ]
}

AddTodoLabelRequest

object
label_idstringrequired

Identifier

Example
{
  "label_id": "vM7Lp2q"
}

CreateTodoBoardRequest

object
namestringrequired
created_bystring | null

Identifier

Example
{
  "name": "string",
  "created_by": "vM7Lp2q"
}

UpdateTodoBoardRequest

object
namestring | null
Example
{
  "name": "string"
}

CreateTodoBoardListRequest

object
namestringrequired
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

Example
{
  "name": "string",
  "text_color": "string",
  "background_color": "string",
  "created_by": "vM7Lp2q"
}

UpdateTodoBoardListRequest

object
namestring | null
text_colorstring | null
background_colorstring | null
Example
{
  "name": "string",
  "text_color": "string",
  "background_color": "string"
}

CreateTodoLabelRequest

object
namestringrequired
text_colorstring | null
background_colorstring | null
created_bystring | null

Identifier

Example
{
  "name": "string",
  "text_color": "string",
  "background_color": "string",
  "created_by": "vM7Lp2q"
}

UpdateTodoLabelRequest

object
namestring | null
text_colorstring | null
background_colorstring | null
Example
{
  "name": "string",
  "text_color": "string",
  "background_color": "string"
}

OkResponse

object
statusstringokrequired
datastring | null

Always null for delete responses

Example
{
  "status": "ok",
  "data": "string"
}

ErrorBody

object
codestringrequired

Stable machine-readable error code.

status_codeinteger<int32>required

HTTP status code for this response.

messagestringrequired

Human-readable error message.

Example
{
  "code": "string",
  "status_code": 0,
  "message": "string"
}

ErrorResponse

object
statusstringerrorrequired
errorobjectrequired
Show child attributes
codestringrequired

Stable machine-readable error code.

status_codeinteger<int32>required

HTTP status code for this response.

messagestringrequired

Human-readable error message.

Example
{
  "status": "error",
  "error": {
    "code": "string",
    "status_code": 0,
    "message": "string"
  }
}

RecordSearchFilterClause

object
fieldstringrequired
opstringrequired
valueany
Example
{
  "field": "status",
  "op": "contains"
}

RecordSearchFilterGroup

object
opstringrequired
clausesArray<object>required
Show child attributes
fieldstringrequired
opstringrequired
valueany
Example
{
  "op": "and",
  "clauses": [
    {
      "field": "status",
      "op": "contains"
    }
  ]
}

RecordSearchSort

object
fieldstringrequired
directionstringrequired
Example
{
  "field": "created_at",
  "direction": "desc"
}

SearchRecordsRequest

object
querystring

Search 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.

Show child attributes
opstringrequired
clausesArray<object>required
Show child attributes
fieldstringrequired
opstringrequired
valueany
sortArray<object>

Sort fields. Empty or omitted values default to created_at desc.

Show child attributes
fieldstringrequired
directionstringrequired
Example
{
  "query": "*",
  "limit": 10,
  "offset": 0,
  "filters": [
    {
      "op": "and",
      "clauses": [
        {
          "field": "status",
          "op": "contains"
        }
      ]
    }
  ],
  "sort": [
    {
      "field": "created_at",
      "direction": "desc"
    }
  ]
}

TodoSearchHit

object
idstringrequired

Public todo SqID stored in the index metadata.

scorenumber<float>required
attributesobjectrequired
Show child attributes
[key: string]any
Example
{
  "id": "encoded-todo-sqid",
  "score": 0.75,
  "attributes": {}
}

TodoSearchData

object
countinteger<int32>required
resultsArray<object>required
Show child attributes
idstringrequired

Public todo SqID stored in the index metadata.

scorenumber<float>required
attributesobjectrequired
Show child attributes
[key: string]any
Example
{
  "count": 1,
  "results": [
    {
      "id": "encoded-todo-sqid",
      "score": 0.75,
      "attributes": {}
    }
  ]
}

TodoSearchResponse

object
statusstringrequired
dataobjectrequired
Show child attributes
countinteger<int32>required
resultsArray<object>required
Show child attributes
idstringrequired

Public todo SqID stored in the index metadata.

scorenumber<float>required
attributesobjectrequired
Show child attributes
[key: string]any
Example
{
  "status": "ok",
  "data": {
    "count": 1,
    "results": [
      {
        "id": "encoded-todo-sqid",
        "score": 0.75,
        "attributes": {}
      }
    ]
  }
}