Docs
API referencePeople and H R

Add a document

Preview· P9
POST
/people/{person_id}/documents

Adds a standard document to a person's record. Send the file as the request body (a PDF, or a photo as JPEG, PNG or WebP, up to 20 MB) and its type and details in the query. Agoo checks the file by its bytes, removes a photo's camera details and location, encrypts it with a key of its own and scans it for viruses; the document is checking until the scan passes. Send replaces to add the next version of a current document (a renewed licence): the older one is kept as superseded.

  • A type that expires needs expires_on; Agoo reminds the person, their manager and HR before it expires, as the type says, and fires hr_document.expiring.
  • A copy of a Ghana Card is refused (L.I. 2523 forbids relying on a photocopy, scan or image of one to verify identity): record the Ghana Card PIN on the HR record instead.
  • HEIC photos and Word files are refused: send a JPEG or a PDF.

Scope: documents: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: documents:write

Path Parameters

person_id*string

The person's ID.

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

Query Parameters

type_id*string

The document's type (its organisation's types are in the Console, under People, Documents).

Match^hrdoctype_[0-7][0-9a-hjkmnp-tv-z]{25}$
Example"hrdoctype_01m6k1z8b0d2f4h6k8m0p2r4tw"
title?string

The type's name when left out.

Lengthlength <= 160
issued_on?string
Match^[0-9]{4}-[0-9]{2}-[0-9]{2}$
expires_on?string

Required for a type that expires.

Match^[0-9]{4}-[0-9]{2}-[0-9]{2}$
notes?string
Lengthlength <= 500
replaces?string

The current document this one replaces: it becomes the next version.

Match^hrdoc_[0-7][0-9a-hjkmnp-tv-z]{25}$
Example"hrdoc_01m6k2a4c6e8g0j2r4n6q8s0tv"
file_name?string
Lengthlength <= 160

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

body*fileapplication/octet-stream
Formatbinary

Response Body

The document, checking until its virus scan passes.

application/json
  1. response

One version of a person's HR document, without the file (Download a document). Through the API, standard documents only: identity documents, disciplinary letters and health documents stay inside Agoo.

id*HrDocumentId

An HR document ID (TypeID with the hrdoc prefix): one version of a document.

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

A person ID (TypeID with the person prefix).

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

A document's type, as the document names it.

title*string
version*integer
Range1 <= value
supersedes_id*|

The version it replaced.

status*string

checking until its virus scan passes; then current (or expired past its date); superseded once a newer version is in force; refused when the scan or the check of its bytes failed (its file was deleted).

Value in"checking""current""expired""superseded""refused"
visibility*"standard"

Through the API, standard documents only.

Value in"standard"
issued_on*|
Formatdate
expires_on*|
Formatdate
content_type*string
Value in"application/pdf""image/jpeg""image/png""image/webp"
byte_size*integer
sha256*string

Hex SHA-256 of the file, so a copy proves itself.

created_at*string
Formatdate-time
updated_at*string
Formatdate-time
curl -X POST 'https://api.agoohq.com/v1/people/person_01kjsesxm0e4zbyvkr7bcfxbfg/documents?type_id=hrdoctype_01m6k1z8b0d2f4h6k8m0p2r4tw' \  -H 'Idempotency-Key: 3f6b2a1e-8c4d-4f7a-9b2e-5d1c0a7e9f64' \  -H 'Content-Type: application/octet-stream' \  -d 'string'
{  "id": "hrdoc_01m6k2a4c6e8g0j2r4n6q8s0tv",  "object": "hr_document",  "person_id": "person_01kjw4mg80efgb5aqbsqnxhtbh",  "type": {    "id": "hrdoctype_01m6k1z8b0d2f4h6k8m0p2r4tw",    "name": "Professional licence",    "category": "licence"  },  "title": "Medical and Dental Council licence",  "version": 2,  "supersedes_id": "hrdoc_01m3f8c0e2g4j6r8n0q2s4v6wy",  "status": "checking",  "visibility": "standard",  "issued_on": "2026-01-02",  "expires_on": "2026-12-31",  "content_type": "application/pdf",  "byte_size": 176004,  "sha256": "9f2c0b8e4d1a7c3e5b6f8a0d2c4e6f8a1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a",  "created_at": "2026-01-04T09:12:00Z",  "updated_at": "2026-01-04T09:14:00Z"}