Beneficiary Documents
Identity documents and supporting files attached to a beneficiary. All routes are nested under the beneficiary and require the registre.documents permission.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/beneficiaires/{beneficiaireId}/documents | List documents |
| POST | /api/beneficiaires/{beneficiaireId}/documents | Upload a document |
| GET | /api/beneficiaires/{beneficiaireId}/documents/types | Accepted document types |
| GET | /api/beneficiaires/{beneficiaireId}/documents/{documentId} | Document metadata |
| GET | /api/beneficiaires/{beneficiaireId}/documents/{documentId}/download | Download the file |
| POST | /api/beneficiaires/{beneficiaireId}/documents/{documentId}/verify | Verify the document |
| POST | /api/beneficiaires/{beneficiaireId}/documents/{documentId}/reject | Reject the document |
| DELETE | /api/beneficiaires/{beneficiaireId}/documents/{documentId} | Delete the document |
An unknown beneficiary or document returns 404 ({"error": "Beneficiaire non trouve"} or Document non trouve).
GET /api/beneficiaires/{beneficiaireId}/documents
Optional parameters: type (document type) and status (pending, verified, rejected). Deleted documents are excluded.
{
"success": true,
"data": [
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"beneficiaireId": "550e8400-e29b-41d4-a716-446655440000",
"type": "cni",
"typeLabel": "Carte Nationale d'Identite",
"originalFilename": "cni.pdf",
"mimeType": "application/pdf",
"fileSize": 245760,
"fileSizeFormatted": "240.00 KB",
"verificationStatus": "verified",
"verifiedAt": "2026-01-20 14:30:00",
"verifiedBy": "Agent Exemple",
"rejectionReason": null,
"notes": null,
"expiryDate": "2030-06-15",
"isExpired": false,
"uploadedBy": "Agent Exemple",
"createdAt": "2026-01-15 10:30:00",
"updatedAt": null
}
],
"total": 1
}
Document types
| Type | Description |
|---|---|
| cni | National Identity Card |
| certificat_residence | Residence Certificate |
| acte_naissance | Birth Certificate |
| photo | Identity Photo |
| certificat_scolaire | School Certificate |
| certificat_medical | Medical Certificate |
| justificatif_revenu | Proof of Income |
| contrat_signe | Signed Contract |
| autre | Other Document |
The current list is returned by GET /api/beneficiaires/{beneficiaireId}/documents/types.
POST /api/beneficiaires/{beneficiaireId}/documents
Sent as multipart/form-data.
| Field | Type | Required | Description |
|---|---|---|---|
| file | file | Yes | File (PDF, JPEG, PNG or WebP, 10 MB at most) |
| type | string | Yes | Document type (list above) |
| expiryDate | date | No | Expiry date (YYYY-MM-DD) |
| notes | string | No | Additional notes |
Response 201 Created: { "success": true, "message": "Document uploade avec succes", "data": { … } }. A missing file, unknown type, or rejected format or size returns 400.
curl -X POST https://sig.example.com/api/beneficiaires/550e8400-e29b-41d4-a716-446655440000/documents \
-H "Authorization: Bearer TOKEN" \
-F "type=cni" \
-F "file=@/chemin/vers/cni.pdf" \
-F "expiryDate=2030-06-15"
POST …/documents/{documentId}/verify
Optional body: { "notes": "…" }. Sets the document to verified. A document already verified or rejected returns 400 Document deja traite.
POST …/documents/{documentId}/reject
{ "reason": "Document illisible, merci d'envoyer une copie plus nette" }
reason is required (400 Motif de rejet requis). Same rule as verification for an already processed document.
DELETE …/documents/{documentId}
Soft delete: the document disappears from lists but the file is kept. An administrator can force physical deletion with ?hard=true; for other roles the parameter is ignored.
Response: { "success": true, "message": "Document supprime" }.
JavaScript example
const base = (id) => `https://sig.example.com/api/beneficiaires/${id}/documents`;
const headers = { Authorization: `Bearer ${token}` };
const { data } = await (await fetch(base(beneficiaireId), { headers })).json();
const form = new FormData();
form.append('type', 'cni');
form.append('file', fichier);
await fetch(base(beneficiaireId), { method: 'POST', headers, body: form });
await fetch(`${base(beneficiaireId)}/${documentId}/reject`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ reason: 'Document illisible' }),
});