Change a person's job
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_idputs them in a position nobody holds that isn't frozen or closed (and out of the one they held);nulltakes them out of theirs. Positions are part of Growth, Pro and Enterprise.manager_idmust be an active person in your directory, never the person themselves.- Fires
person.job_changedwhen it's applied: at once, or on its date.
Scope: hr:write · Plan: Pro and Enterprise in live mode; every plan in test mode.
AuthorizationBearer <token>Send Authorization: Bearer <token> on every request. The token is one of:
| Prefix | What it is | Where it may be used |
|---|---|---|
agoo_sk_live_ | Secret key, live mode | Your servers only |
agoo_sk_test_ | Secret key, test mode | Your servers only |
agoo_pk_live_ | Publishable key, live mode | Browsers 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 mode | As 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
person_id*stringThe person's ID.
^person_[0-7][0-9a-hjkmnp-tv-z]{25}$"person_01kjsesxm0e4zbyvkr7bcfxbfg"Idempotency-Key*stringA 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.
uuidapplication/json- body
What changes, and from when. Send at least one field; null clears an optional one.
job_title?|length <= 120grade?|length <= 60department_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<>1 <= items <= 50employment_type?EmploymentTypeHow they're employed. New people are permanent unless you say otherwise.
"permanent""temporary""casual""part_time"contract_type?ContractTypeopen_ended, fixed_term, casual, apprenticeship, national_service or internship.
"open_ended""fixed_term""casual""apprenticeship""national_service""internship"contract_ends_on?|dateprobation_ends_on?|datecontracted_hours?|Contracted hours a week.
0.5 <= value <= 80effective_on?stringThe day it takes effect: today when left out, up to 90 days back or a year ahead.
datereason?stringlength <= 500The job change: applied, or scheduled for its date.
application/json- 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*JobChangeIdA job change ID (TypeID with the pchg prefix).
^pchg_[0-7][0-9a-hjkmnp-tv-z]{25}$"pchg_01m6j4p2r6t0v4x8z2b6d0f4hm"object*"job_change""job_change"person_id*PersonIdA person ID (TypeID with the person prefix).
^person_[0-7][0-9a-hjkmnp-tv-z]{25}$"person_01kjsesxm0e4zbyvkr7bcfxbfg"status*JobChangeStatuspending: waiting for approval. scheduled: to be applied on its date. applied. declined. cancelled: called off. failed: it couldn't be applied on its date.
"pending""scheduled""applied""declined""cancelled""failed"source*stringWho made it: HR in the Console, their line manager, the person themselves, or the API.
"hr""manager""self""api"effective_on*stringdatereason*string|nullfields*array<>failure*|Why it couldn't be applied on its date.
created_at*stringdate-timeapplied_at*|date-timecurl -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}List a person's job changes GET
Returns the person's job changes, newest first (up to 200): waiting for approval (`pending`), `scheduled` for their date, `applied`, `declined`, `cancelled`, or `failed` when one couldn't be made on its date (`failure` says why). **Scope:** `hr:read` · **Plan:** Pro and Enterprise in live mode; every plan in test mode.
List a person's documents GET
Returns a person's standard HR documents (contracts, letters, certificates, licences) as metadata, newest first: the latest version of each document, or every version with `versions=true`. A document is `checking` until its virus scan passes, then `current` (or `expired` past its date), and `superseded` once a newer version is in force. Identity documents, disciplinary letters and health documents (medical certificates, police reports) are never returned to an API key: they stay inside Agoo. **Scope:** `documents:read` · **Plan:** Pro and Enterprise in live mode; every plan in test mode.