Approve or decline a leave request
Approves or declines a request waiting for a decision, all its approval steps at once (your organisation's
approvers decide step by step in Agoo Workspace and the Console). A decline needs a note the person sees; a
type that can't be declined (maternity: the dates are agreed, Labour Act s.57) can only be approved; approving
stays within the balance. A request that isn't waiting returns invalid_state. leave.approved or
leave.declined fires.
Scope: attendance:manage · 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: attendance:manage
leave_id*stringThe leave request's ID.
^leave_[0-7][0-9a-hjkmnp-tv-z]{25}$"leave_01m4z0q2k8fv7tqz3x9c1nbe5d"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
decision*string"approve""decline"note?stringRequired to decline (3 to 300 characters): the person sees it.
length <= 300The leave request, decided.
application/json- response
A leave request. A private type (sick and maternity by default) comes back as kind: away, without its type, reason or note.
id*LeaveRequestIdA leave request ID (TypeID with the leave prefix).
^leave_[0-7][0-9a-hjkmnp-tv-z]{25}$"leave_01m4z0q2k8fv7tqz3x9c1nbe5d"person_id*PersonIdA person ID (TypeID with the person prefix).
^person_[0-7][0-9a-hjkmnp-tv-z]{25}$"person_01kjsesxm0e4zbyvkr7bcfxbfg"type_id*|null for a private type.
^ltype_[0-7][0-9a-hjkmnp-tv-z]{25}$type_name*string"Annual leave""Away"kind*string"annual""sick""maternity""paternity""compassionate""study""unpaid""other""away"private*booleanstatus*string"pending""approved""declined""cancelled"starts_on*stringdateends_on*stringThe last day of leave.
datehalf_day*booleanhalf_day_part*|"morning""afternoon"nulldays*numberWhat it counts, in unit.
3unit*string"working_days""calendar_days"paid*booleanreason*|The person's note; null for a private type.
decision_note*|The approver's note; null for a private type.
decided_at*|date-timedecided_by*|Who decided it; null when recorded, decided through the API or approved at once.
^person_[0-7][0-9a-hjkmnp-tv-z]{25}$approval*|The approval's state; null when it needed none.
cancelled_at*|date-timecreated_at*stringdate-timeupdated_at*stringdate-timecurl -X POST 'https://api.agoo.ardent.africa/v1/leave-requests/leave_01m4z0q2k8fv7tqz3x9c1nbe5d/decide' \ -H 'Idempotency-Key: 3f6b2a1e-8c4d-4f7a-9b2e-5d1c0a7e9f64' \ -H 'Content-Type: application/json' \ -d '{ "decision": "approve"}'{ "id": "leave_01m4z0q2k8fv7tqz3x9c1nbe5d", "person_id": "person_01kjw4mg80efgb5aqbsqnxhtbh", "type_id": "ltype_01m4y8r6t0e9k2b7c5d3f1g0hj", "type_name": "Annual leave", "kind": "annual", "private": false, "status": "approved", "starts_on": "2026-11-16", "ends_on": "2026-11-18", "half_day": false, "half_day_part": null, "days": 3, "unit": "working_days", "paid": true, "reason": "Family visit in Ho", "decision_note": null, "decided_at": "2026-10-15T08:30:00Z", "decided_by": null, "approval": { "status": "approved", "step": null, "of": 2 }, "cancelled_at": null, "created_at": "2026-10-14T09:12:00Z", "updated_at": "2026-10-15T08:30:00Z"}Get a leave request GET
Returns one leave request. A private type comes back as `away`. **Scope:** `attendance:read` · **Plan:** Pro and Enterprise in live mode; every plan in test mode.
Cancel a leave request POST
Cancels a request waiting for a decision, or approved leave that hasn't started (its days come back to the balance). Leave that has started returns `invalid_state`: HR ends it early in the Console. `leave.cancelled` fires. **Scope:** `attendance:manage` · **Plan:** Pro and Enterprise in live mode; every plan in test mode.