Bulk Uploads
Requires partner / operator authorization. See CMS → Home.
Create thousands of cardholders (or issue thousands of cards) in one operation. Progress streams via Server-Sent Events so the CMS UI can show a live progress bar.
Upload cardholders
The cardholder upload uses the form field users:
curl -X POST "https://api.ali.app/cms/rest/app/partners/{partnerId}/cardholders/upload" \
-H "Authorization: Bearer <token>" \
-H "x-user-token: Bearer <cms-user-token>" \
-F "users=@cardholders.xlsx"
Accepts only .xlsx / .xls (CSV is rejected). The only limit is a 16 MB file size — there is no row-count cap.
Response (HTTP 200):
{
"success": true,
"message": "...",
"data": {
"id": "bat_01HAAA"
}
}
data.id is the batch ID used to subscribe to the SSE progress stream.
Required columns (Excel)
name,lastName,address,countryOfBirth,dateOfBirth,maritalStatus,gender,phoneNumber,email,documentType,documentNumber,cardId
María,Ramírez,Calle Principal 123,GT,1990-05-12,soltero,F,50255551234,maria@example.com,DPI,2345678901234,1
Juan,Pérez,Av. Reforma 45,GT,1985-12-03,casado,M,50255559999,juan@example.com,DPI,9876543210987,2
All columns are required. Enum values match the single-cardholder create payload (maritalStatus, gender, documentType, countryOfBirth, dateOfBirth); cardId is the numeric card to assign.
Upload cards (batch-issue)
The card upload uses the form field cards:
curl -X POST "https://api.ali.app/cms/rest/app/partners/{partnerId}/cards/upload" \
-H "Authorization: Bearer <token>" \
-H "x-user-token: Bearer <cms-user-token>" \
-F "cards=@cards.xlsx"
Progress tracking via SSE
Open a long-lived HTTP connection to receive real-time progress:
curl "https://api.ali.app/cms/rest/app/partners/{partnerId}/cardholders/batch/{batchId}/progress" \
-H "Authorization: Bearer <token>" \
-H "x-user-token: Bearer <cms-user-token>" \
-H "Accept: text/event-stream" \
--no-buffer
The stream emits unnamed data: frames (no event: line). Each frame carries:
data: {"batchId":"bat_01HAAA","timestamp":"2026-03-01T10:00:00Z","stage":"processing","total":5423,"processed":2400,"successful":2378,"failed":22,"percentage":44,"message":"..."}
data: {"batchId":"bat_01HAAA","timestamp":"2026-03-01T10:01:00Z","stage":"completed","total":5423,"processed":5423,"successful":5380,"failed":43,"percentage":100,"message":"..."}
Use the stage field to detect completion. Possible values: processing, completed, error, timeout.
Browser EventSource example
const es = new EventSource(`/cms/rest/app/partners/${partnerId}/cardholders/batch/${batchId}/progress`, {
withCredentials: true,
});
es.onmessage = (e) => {
const p = JSON.parse(e.data);
setProgress(p.percentage);
if (p.stage === 'completed' || p.stage === 'error' || p.stage === 'timeout') {
es.close();
}
};
SSE progress is in-memory and single-pod only. NATS progress events are fire-and-forget — if no listener is attached when an event fires, that event is lost. The connection also closes after an inactivity timeout (emitting a stage: "timeout" frame).