Your workflow.
Our API.
The API provides access to the same profiles, files, applications and events as the member portal. Every request is limited by data ownership and the API key scopes.
Create an API key ↗Download the OpenAPI 3.1 JSON specification for Postman, code generators and other tools.
1. Create and store a key
Open Member portal → API access → Create key. Set an integration name, expiry date and the smallest required scope set. The token is shown once. Store it on your server in an environment variable; never put it in public JavaScript.
Authorization: Bearer YOUR_TOKEN
Accept: application/json
Bearer requests do not require CSRF. A browser session must first call GET /api/v1/session and then send X-CSRF-Token with every state-changing request. Cross-origin browser access is disabled by default, so third-party integrations should call the API from their server.
Registration, password recovery requests and the contact form require a one-use CAPTCHA. In the same session call GET /captcha?purpose=register|forgot|contact, render the PNG in data.image, then submit captcha_id and the five displayed characters as captcha_answer. A challenge lasts 10 minutes and one attempt; issuing a newer challenge invalidates the previous one.
2. Make the first request
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://nw.fams.kz/api/v1/profiles
{
"data": [{"id": 123, "kind": "athlete", "name": "Athlete name"}],
"meta": {},
"request_id": "request identifier"
}
3. Upload a file and attach a passport
JPG, PNG, WebP and PDF files up to 20 MB are accepted. Files are stored outside the public directory. Keep the returned data.id and pass it as file_id or photo_id.
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-F "file=@passport.pdf" -F "purpose=identity" \
https://nw.fams.kz/api/v1/files
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"profile_id":123,"type":"passport","file_id":"FILE_UUID","number":"N1234567","country":"Kazakhstan","issued_at":"2025-01-15","expires_at":"2035-01-15"}' \
https://nw.fams.kz/api/v1/documents
Both identity and passport satisfy the identity-document requirement. Other types are driver, medical, consent and organization. Foreign passport numbers may contain letters and an IIN is optional.
Rejection reasons: review_note is returned for documents in GET /profiles/{id} and GET /applications/{id}. Show it when the status is rejected or changes. An administrator must supply a 5–3000 character reason when returning or rejecting a document.
Core routes
| Method and path after /api/v1 | Purpose | Scope |
|---|---|---|
| GET /catalog?kind=service | Services and pricing | Public |
| GET /services/prices | Current MRP and exact KZT price of every active service | applications:read |
| GET, POST /profiles | List or create profiles | profiles:read / profiles:write |
| GET /profiles/summary | Compact athlete directory with document, application, certificate and event counters | profiles:read |
| GET /profiles/{id}/portfolio | One athlete portfolio with profile, documents, certificates, applications and event entries | profiles:read, owner only |
| PATCH /profiles/{id} | Update profile details or photo | profiles:write |
| POST /profiles/{id}/submit | Submit a profile for review | profiles:write |
| POST /documents | Attach a document to a profile | profiles:write |
| GET, POST /files | List or upload files | files:read / files:write |
| GET /applications | List your applications | applications:read |
| POST /applications/quote | Calculate the server-side price | applications:write |
| POST /applications | Create an application draft | applications:write |
| POST /applications/{id}/submit | Validate and submit an application | applications:write |
| POST /applications/{id}/pay | Pay from the balance with duplicate-charge protection | wallet:write |
| GET /applications/{id}/certificate | Download an approved and paid document | applications:read |
| PUT /applications/{id}/sharing | Enable or revoke international licence documents via QR | applications:write, owner only |
| GET /applications/{id}/qr | Download the QR code for an approved, paid international licence | applications:read |
| GET /event-registrations | List own competition entries | applications:read |
| GET /events/{id}/registration-options | Eligible valid certificates for the event | applications:read |
| POST /events/{id}/register | Submit an athlete entry; no submission payment | applications:write |
| GET /events/{id}/registrations | List athlete entries for the organiser | events:read |
| PATCH /events/{id}/registrations/{registration_id} | Approve, return with a reason, or reject | events:write |
| GET /messenger | Allowed conversations only: administration and related competitions | notifications:read |
| GET /messenger/{perspective}/registrations/{id} | Conversation for one competition entry | notifications:read |
| POST /messenger/{perspective}/registrations/{id}/messages | Message the server-resolved allowed recipient | notifications:write |
| GET, POST /events | List events or create a draft | events:read / events:write |
| GET /events/public/{id} | Published event, documentation status and approved standings | Public |
| GET /events/public/{id}/documents/{regulations|results} | Approved regulations or final results; add ?download=1 to download | Public after approval |
| PATCH /events/{id} | Update an event or one of its files | events:write |
| GET, POST /events/{id}/participants | List participants or add one by certificate | events:read / events:write |
| PATCH, DELETE /events/{id}/participants/{application_id} | Update a standing or remove a participant before submission | events:write |
| GET /wallet | Balance, invoices and transaction history | wallet:read |
| GET /notifications | Notifications | notifications:read |
| GET, POST, DELETE /telegram | View, create a one-time link, or disconnect the Telegram bot | Browser session and CSRF for changes |
| GET /verify/{token} | Public verification without personal data | Public |
| GET /verify/{token}/documents | Holder-approved documents for a valid international licence | Public through an approved QR link |
Applications, insurance and money
GET /services/prices is the authoritative rate list for a signed-in user or integration. It returns the current MRP in mrp.amount_minor, each service multiplier in services[].mrp, the Kazakhstan total in price_kz_minor, and the full CIS total in price_cis_minor where that territory is allowed. Values ending in _minor are integer tiyn. Use these values for display and still accept the amount returned when the application is created as final.
Telegram uses the same domain rules as the API. Users link it from the Security page using a single-use 10-minute code; passwords and API keys are never sent to Telegram. The transport webhook is reserved for Telegram and protected by X-Telegram-Bot-Api-Secret-Token. See docs/telegram-bot.md for server setup.
A national certificate always includes its required insurance workflow. Its only payment is the insurance contribution for the chosen category; there is no separate insurance service or switch. The legacy formula remains: category rate × MCI, plus the category CIS surcharge × MCI when that territory is allowed and selected. insurance_coverage_minor is the coverage amount, not the contribution. Do not use response fields to disable insurance.
The server calculates and stores the price. Never submit a client-calculated price. Money fields ending in _minor contain integer tiyn; invoice amount must be a decimal string such as "15000.00". Reuse the same Idempotency-Key and amount when retrying invoice creation after a timeout.
Organiser workflow
- Create a profile with
kind: "organizer", complete its details and wait for approval. - Create an event in
/events. - Download
/events/{id}/agreement, sign it, upload the scan and attach it with stageagreement. - Submit stage
details; pay the contribution application exposed asdata.application_id. - After approval, upload and submit
regulations. - After the event, add each athlete with
POST /events/{id}/participants. Thecertificatefield accepts an exact certificate number, verification token or full QR URL. The server supplies the athlete identity and checks approval, payment and validity for all event dates. Recordcategory,start_number,result_status,placeandresult. - Attach the final PDF and submit stage
results. The registry is locked while the results are under review.
Errors, limits and administrator routes
401 means authentication failed; 403 insufficient scope; 404 missing or foreign-owned record; 409 state, balance or idempotency conflict; 419 CSRF; 422 validation; 429 rate limit; 503 disabled integration. Errors contain error.code, error.message and sometimes error.details. Give support the request_id, never the API key.
List routes accept page and limit from 1 to 100 and return meta.total. Dates use YYYY-MM-DD and Kazakhstan time, UTC+5.
Administrator routes require the administrator role and admin:read / admin:write. GET /admin/athletes lists athlete profiles and supports status, certificate (issued, not_issued, pending) and q filters for name, IIN, phone, city, email or ID. It returns the certificate issue state, latest application, number and validity period together with the account owner and document/application counters. Download the same registry as CSV from GET /admin/export?kind=athletes. Manual balance changes, reversals, permission changes and key management also require a browser session and password confirmation. A bank callback alone never confirms payment; the server verifies the invoice, amount, currency and terminal with the bank.
PUT /admin/profiles/{id}/owner transfers a profile to another active member account. Send current_user_id, target_user_id, a reason of at least five characters and the administrator password. Linked documents, applications, certificates, organiser events, files and competition chat context move atomically. Issued certificate snapshots, paid amounts and ledger entries are preserved. Public QR document access is revoked until the new owner gives consent. Both owners are notified and the action is audited.
National certificates: three lists
GET /admin/national returns national certificates and the current administrator’s separate review, insurance and print lists. Available filters include year, q, service_id, status, paid, insurance, print, page and limit.
POST /api/v1/admin/national/lists/insurance
{"operation":"add","ids":[123,124]}
POST /api/v1/admin/national/lists/insurance/export
{"ids":[123,124]}
Other list operations are remove, clear and auto with a year. A list holds up to 200 records. Insurance and printing require approval and payment. Export returns HTTP 201 with data.file.download_url. Insurance produces XLSX; printing produces a ZIP with document.xlsx, foto/ and qr/. An export mark means only that a file was prepared; the site does not send data to third parties or issue a policy.
Certificate verification and QR document consent
GET /verify/{token} returning HTTP 200 means the record exists; only data.valid confirms validity. The base response excludes names, scans and internal notes. An international licence holder enables access with PUT /applications/{id}/sharing and {"enabled":true,"confirmed":true}, and revokes it with {"enabled":false}. An administrator cannot consent for the holder.
GET /verify/{token}/documents opens only while the licence is approved, paid, currently valid and access is enabled. It returns an allowlisted set of fields and approved scan links, without IIN, phone, address, internal UUIDs or storage paths. Every file link rechecks validity and consent, so revocation takes effect immediately.
An administrator corrects a profile or document metadata with PATCH /admin/records/{profile|document}/{id}, the admin:write scope and the exact updated_at returned by the preceding GET. Review status and the uploaded scan are preserved, the owner is notified, and changed field names are audited. A stale version returns 409. The type of a document attached to an active application is locked, while its other metadata remains editable. Issued certificate snapshots remain unchanged.