Docs
API referencePeople and H R

Change a person's job

Preview· P9
POST
/people/{person_id}/job-changes

Changes the person's job from a date: applied at once when effective_on is today or earlier (up to 90 days back), otherwise scheduled and applied on that day (up to a year ahead). Send at least one field; null clears one that's optional.

  • Each field becomes a line of employment history, dated effective_on.
  • position_id puts them in a position nobody holds that isn't frozen or closed (and out of the one they held); null takes them out of theirs. Positions are part of Growth, Pro and Enterprise.
  • manager_id must be an active person in your directory, never the person themselves.
  • Fires person.job_changed when it's applied: at once, or on its date.

Scope: hr:write · Plan: Pro and Enterprise in live mode; every plan in test mode.

Authorization

headerAuthorizationBearer <token>

Send Authorization: Bearer <token> on every request. The token is one of:

PrefixWhat it isWhere it may be used
agoo_sk_live_Secret key, live modeYour servers only
agoo_sk_test_Secret key, test modeYour servers only
agoo_pk_live_Publishable key, live modeBrowsers and apps: create pre-registrations and bookings, read public booking types (with their intake questions) and their free slots, read the visit types open for pre-registration with their public forms. Never lists people.
agoo_pk_test_Publishable key, test modeAs above, in test mode

Admins create keys in Console → Developers → API keys and choose each key's scopes. A key is shown once. Never put a secret key in a URL, a browser or a mobile app.

Scope: hr:write

Path Parameters

person_id*string

The person's ID.

Match^person_[0-7][0-9a-hjkmnp-tv-z]{25}$
Example"person_01kjsesxm0e4zbyvkr7bcfxbfg"

Header Parameters

Idempotency-Key*string

A UUID you generate for this operation. If you retry with the same key within 24 hours, Agoo returns the original response instead of acting twice. While the first request is still running, a retry returns conflict. Reusing a key with a different request returns idempotency_key_reused. Responses with rate_limited, internal_error or unavailable aren't stored, so retry those with the same key.

Formatuuid

Request Body

application/json
  1. body

What changes, and from when. Send at least one field; null clears an optional one.

job_title?|
Lengthlength <= 120
grade?|
Lengthlength <= 60
department_id?|

One of your departments that isn't archived.

position_id?|

A position nobody holds that isn't frozen or closed. null takes them out of theirs.

manager_id?|

Their line manager: an active person, never themselves.

site_ids?array<>
Items1 <= items <= 50
employment_type?EmploymentType

How they're employed. New people are permanent unless you say otherwise.

Value in"permanent""temporary""casual""part_time"
contract_type?ContractType

open_ended, fixed_term, casual, apprenticeship, national_service or internship.

Value in"open_ended""fixed_term""casual""apprenticeship""national_service""internship"
contract_ends_on?|
Formatdate
probation_ends_on?|
Formatdate
contracted_hours?|

Contracted hours a week.

Range0.5 <= value <= 80
effective_on?string

The day it takes effect: today when left out, up to 90 days back or a year ahead.

Formatdate
reason?string
Lengthlength <= 500

Response Body

The job change: applied, or scheduled for its date.

application/json
  1. response

A change to a person's job effective from a date, made by HR, proposed by their line manager, asked for by the person, or made through the API.

id*JobChangeId

A job change ID (TypeID with the pchg prefix).

Match^pchg_[0-7][0-9a-hjkmnp-tv-z]{25}$
Example"pchg_01m6j4p2r6t0v4x8z2b6d0f4hm"
object*"job_change"
Value in"job_change"
person_id*PersonId

A person ID (TypeID with the person prefix).

Match^person_[0-7][0-9a-hjkmnp-tv-z]{25}$
Example"person_01kjsesxm0e4zbyvkr7bcfxbfg"
status*JobChangeStatus

pending: waiting for approval. scheduled: to be applied on its date. applied. declined. cancelled: called off. failed: it couldn't be applied on its date.

Value in"pending""scheduled""applied""declined""cancelled""failed"
source*string

Who made it: HR in the Console, their line manager, the person themselves, or the API.

Value in"hr""manager""self""api"
effective_on*string
Formatdate
reason*string|null
fields*array<>
failure*|

Why it couldn't be applied on its date.

created_at*string
Formatdate-time
applied_at*|
Formatdate-time
curl -X POST 'https://api.agoohq.com/v1/people/person_01kjsesxm0e4zbyvkr7bcfxbfg/job-changes' \  -H 'Idempotency-Key: 3f6b2a1e-8c4d-4f7a-9b2e-5d1c0a7e9f64' \  -H 'Content-Type: application/json' \  -d '{  "job_title": "Senior operations officer",  "grade": "G6",  "position_id": "pos_01m6h2k4q8e7r9t1v3w5x7y9za",  "effective_on": "2026-11-01",  "reason": "Promotion after the 2026 review"}'
{  "id": "pchg_01m6j4p2r6t0v4x8z2b6d0f4hm",  "object": "job_change",  "person_id": "person_01kjw4mg80efgb5aqbsqnxhtbh",  "status": "scheduled",  "source": "api",  "effective_on": "2026-11-01",  "reason": "Promotion after the 2026 review",  "fields": [    {      "field": "job_title",      "label": "Job title",      "from": "Operations officer",      "to": "Senior operations officer"    },    {      "field": "grade",      "label": "Grade",      "from": "G5",      "to": "G6"    },    {      "field": "position_id",      "label": "Position",      "from": null,      "to": "Senior operations officer"    }  ],  "failure": null,  "created_at": "2026-10-19T11:20:00Z",  "applied_at": null}