API and keys
The back office, the portals and the website all use this one REST API. Outside systems get a key with only the scopes they need, and every call is logged.
Requests, last 24 hours
18,420
Website 61%, portals 27%, integrations 12%
Median response time
84 ms
95th percentile 310 ms
Error rate
0.3%
52 errors, 41 of them 404 from the old site
Active keys
7
1 expires in 12 days
Resources
v1List batches
scope: batches:readSample payloads use the records in the finance ledger: order O-5128 (Hassan Reda, B-2612, 11 seats sold), payment PAY-5209, invoice INV-2086.
Request
Response200 OK, 71 ms
Base address https://hub.malyomar.example/v1 is a placeholder host for this prototype. Sample responses use the shared sample data.
Conventions
- Format
- JSON, UTF-8, dates in ISO 8601, Cairo time zone offset included
- Sign-in
- Authorization: Bearer with an API key, or the user's session
- Paging
- limit up to 100 and cursor
- Filtering
- Query fields, for example status=open
- Money
- Integer amount plus currency
- Safe retries
- Idempotency-Key header on every POST
- Versions
- Breaking changes get a new version; v1 is kept 12 months after v2
Errors
| 400 | Field missing or wrong type; the body names the field |
| 401 | Key missing, expired or revoked |
| 403 | Key lacks the scope, or role cannot see the record |
| 404 | No such record |
| 409 | Conflict, for example batch full or duplicate enrolment |
| 423 | Record locked, for example ASME program content |
| 429 | Rate limit reached; see Retry-After |
Resource summary
| Resource | Owned by | Read | Create | Update | Delete | Notes |
|---|
| Name | Key | Scopes | Created by | Last used | Calls, 24 h | Expires | State |
|---|
A key is shown in full once, when created. Creating, rotating and revoking a key are recorded in the audit log.
Scopes
| Scope | Allows | Sensitive |
|---|---|---|
| courses:read | Catalog, paths, academies, instructors' public profiles | No |
| courses:write | Create and edit MALYOMAR programs; ASME content stays locked | Yes |
| batches:read | Dates, mode, seats left | No |
| batches:write | Create batches, change dates and capacity | Yes |
| learners:read | Learner profile, company, enrolments | Personal data |
| learners:write | Create and update learners | Personal data |
| enrolments:write | Enrol, transfer, cancel | Yes |
| orders:read | Orders, invoices, payment status; no card data exists in the hub | Yes |
| orders:write | Create orders, record payments | Money |
| certificates:read | Verify a certificate by number or code | No |
| certificates:issue | Issue or revoke; reserved for the hub's own rules | Restricted |
| leads:write | Create leads from forms and chat | No |
Key expiring. "Accounting sync" expires on 15 October. Rotate it before then or invoices stop posting.
Key rules
- One key per system, named after it, with an owner on staff.
- Smallest set of scopes. Website keys never get learners:read.
- Keys expire after 12 months at most and can be limited to fixed IP addresses.
- Corporate clients read their own learners through a key tied to their account; they cannot see other accounts.
- Only admins create keys. See roles and permissions.
Insight. "Old reporting script" has not made a call in 64 days and still holds learners:read. Unused keys with personal-data scopes should be revoked.
Rate limits
| Caller | Per minute | Per day | Burst | Peak today | When exceeded |
|---|---|---|---|---|---|
| Public website (catalog, schedule) | 600 | 200,000 | 100 | 186 per minute | Serve cached catalog |
| Learner, instructor and corporate portals | 120 per user | No cap | 30 | 22 per minute, one user | 429, retry after 5 s |
| Integration keys (default) | 60 | 20,000 | 20 | 49 per minute, accounting sync | 429 with Retry-After |
| Corporate client keys | 30 | 5,000 | 10 | 3 per minute | 429 with Retry-After |
| Lead form and chat | 10 per IP | 300 per IP | 5 | 4 per minute, one IP | Show a human check |
| Certificate verification (public) | 20 per IP | 500 per IP | 5 | 3 per minute | 429, retry after 60 s |
| Bulk export | 2 jobs | 20 jobs | 1 | 1 job running | Queue the job |
Requests per hour, today
RequestsHour with 429 responses
Calls by resource, 24 hours
Slowest endpoints
| GET /learners?include=enrolments | 410 ms |
| POST /orders | 290 ms |
| GET /batches/{id}/roster | 180 ms |
| GET /courses | 42 ms |
95th percentile.
The accounting sync hit its limit at 10:00 when it retried failed invoices, among them INV-2086 for order O-5128 (customer Hassan Reda not found in the ledger). Fixing the missing customers in connectors removes the retries; the queue itself is on Accounting & ledgers. Simulated: no accounting system is chosen or connected (DEC-01).