Update a placement
Changed onUse this endpoint to partially update an existing placement. Only the fields present in the request body are changed — omitted fields are left untouched.
What you can update:
- startDate — ISO 8601 datetime, or null to clear it
- salary — a { value, currency } object, or null to clear both. This maps to the salary object returned by the GET endpoints
- bonus — a decimal string denominated in the salary currency (there is no separate bonus currency), or null to clear it
- feeIncludesBonus — boolean; null is rejected
- commissionRate — a decimal string, or null to clear it. Unlike creation, no default is applied — the literal value is written
- companyContactId — the hiring contact at the client company. It must belong to your agency, and to the project's company when the project has one; null clears it
- customAttributes — full replace: every existing value not present in the payload is removed. Omit the field to leave values untouched
- addFeeIds / removeFeeIds — link fees from the placement's project to this placement, or unlink fees currently linked to it
Permissions: Only the placement owner or an admin (a user with the Agency.update or Placement.update scope) can update a placement. The acting user is the one tied to your API key — a key whose user is neither returns 403, as does a key with no user at all.
Behaviour notes:
- The body must be sent with Content-Type: application/json — any other content type is rejected with 415 so a payload is never silently discarded
- A request with no body at all is rejected with 422. An explicit empty object ({}) is the documented no-op: it returns 200 and writes nothing
- Soft-deleted placements return 404 — they cannot be updated
- A body that changes nothing still returns 200, but no placement.updated webhook is emitted
- A change to a scalar field (startDate, salary, bonus, feeIncludesBonus, commissionRate, companyContactId) emits the placement.updated webhook. The payload is a full snapshot of the placement, not a diff — compare it against the previous event to see what changed. Fee link/unlink and custom-attribute changes do not emit a webhook
What you get back: The full updated placement in the same shape as Get placement details, including nested salary, bonus, feeIncludesBonus, commissionRate, candidate, project, client, fees and customAttributes.
Request
- Base URLhttps://api.recruitwithatlas.com
- AuthHTTP bearer
- TypeScriptA function with typed inputs. Its response is checked against the schema.
Path parameters
Placement ID
Request body
Example request
{
"startDate": "2026-09-01T00:00:00Z",
"salary": {
"value": "25000.00",
"currency": "USD"
},
"bonus": "5000.00",
"commissionRate": "20.00"
}Response
The updated placement, in the same shape as Get placement details
Example response
{
"data": {
"type": "permanent",
"salary": {
"value": "15000",
"currency": "GBP"
},
"bonus": "5000",
"commissionRate": "20",
"approvalStatus": "pending",
"owner": {
"name": "Jane Smith",
"email": "jane@agency.com"
},
"candidate": {
"name": "John Doe",
"role": "Senior Software Engineer",
"company": "Acme Corp",
"owner": {
"name": "Jane Smith"
}
},
"project": {
"owner": {
"name": "Jane Smith"
}
},
"client": {
"company": {
"name": "Acme Corp"
},
"companyContact": {
"name": "Bob Client"
}
},
"fees": [
{
"feeType": {
"name": "Placement Fee"
},
"feeDate": "2025-06-15",
"amount": {
"value": "15000",
"currency": "GBP"
},
"amountInAgencyCurrency": {
"value": "15000",
"currency": "GBP"
},
"projectFeeStatus": "earned",
"createdBy": {
"name": "Jane Smith"
},
"splits": [
{
"feeEarner": {
"name": "Jane Smith",
"email": "jane@agency.com"
},
"feeType": {
"name": "Placement Fee"
},
"share": "60.00"
}
]
}
]
}
}Changes
- warning
added the new
undefinedenum value to the/response property for the response status - warning
added the new
undefinedenum value to the///response property for the response status - warning
added the new
undefinedenum value to the/response property for the response status
- warning
- info
added the required property
/to the response with the status
- info