Update a fee
Changed onUse this endpoint to partially update an existing fee. Omitted fields are left untouched.
Amount & currency: amount is a decimal string (matching what the read endpoints return). Changing amount, currency or feeDate recomputes defaultAmount in the agency currency using the FX rate for the fee date.
Status: fees progress projected → earned → invoiced → paid. Setting projected is rejected with a 422 when the fee would still be linked to a placement after the update — including a placement picked up by relinking personId in the same request (such fees are at least earned). A change to paid stamps paidAt; a change to invoiced stamps invoicedAt.
Clearing text fields: notes and invoiceAccountCode are cleared by sending null. Empty and whitespace-only strings are rejected with a 422 rather than silently stored — otherwise the value written ("") and the value read back (null) would disagree.
Relinking: personId requires projectId, which must match the fee’s own project (a fee cannot be moved to another project — 422 otherwise), and rewires placementId to that candidate’s placement on the project (or null when there is none). Passing personId: null detaches the person and the placement.
Splits: the splits array is a full replacement, not a merge. [] removes every split. In a non-empty array, items with an id update that split, items without an id create a new one, and any existing split not listed is removed. Shares must total exactly 100, and the same split id may appear at most once per request (422 otherwise).
Body rules: the body must be sent with Content-Type: application/json (charset parameters are accepted) — 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 leaves every field unchanged.
What you get back: The full updated fee record with all of its splits — the same shape as GET /api/v1/fees/{id}.
Request
- Base URLhttps://api.recruitwithatlas.com
- AuthHTTP bearer
- TypeScriptA function with typed inputs. Its response is checked against the schema.
Path parameters
Fee ID
Request body
Example request
{
"amount": "15000.00",
"currency": "GBP",
"feeDate": "2025-06-15",
"projectFeeStatus": "earned",
"feeTypeId": "990e8400-e29b-41d4-a716-446655440004",
"personId": "aa0e8400-e29b-41d4-a716-446655440005",
"projectId": "550e8400-e29b-41d4-a716-446655440000",
"splits": [
{
"id": "770e8400-e29b-41d4-a716-446655440002",
"feeEarnerId": "880e8400-e29b-41d4-a716-446655440003",
"feeTypeId": "990e8400-e29b-41d4-a716-446655440004",
"share": "60.00"
}
]
}Response
Fee updated
Example response
{
"data": {
"feeType": {
"name": "Placement Fee"
},
"feeDate": "2025-06-15",
"amount": "15000.00",
"defaultAmount": "15000.00",
"currency": "GBP",
"defaultCurrency": "GBP",
"projectFeeStatus": "earned",
"splits": [
{
"feeEarner": {
"name": "Jane Smith",
"email": "jane@agency.com"
},
"feeType": {
"name": "Placement Fee"
},
"share": "60.00"
}
]
}
}Changes
- info
added the non-success response with the status
- info
added the optional property
to the response with the status
- info