APW Wallet API
პარტნიორული API, ვერსია 1: რეგისტრაცია, შესვლა, პაროლის აღდგენა, პროფილი, ლიმიტები და შეტყობინებები, კომუნალური და სხვა სერვისების გადახდა, საფულიდან საფულეში გადარიცხვა, ვალუტის კურსი და გადაცვლა, ბანკომატიდან გატანა, ვერიფიკაცია და ოპერაციების ისტორია.
მიმოხილვა
ბაზური მისამართი:
https://wallet.apw.ge/api/v1
ყველა მოთხოვნა არის POST და მისი ტანი JSON-ია (Content-Type: application/json), ცარიელი ტანის ჩათვლით.
ავტორიზაცია ორ დონეზე ხდება:
- პარტნიორი: ყოველ მოთხოვნას თქვენი სერვერი HMAC ხელმოწერით აწერს ხელს. ასე ვიცით, რომ მოთხოვნა თქვენგანაა.
- საფულის მომხმარებელი: შესვლის შემდეგ მიღებულ
access_token-სAuthorization: Bearer …header-ში აგზავნით. ეს ზუსტად ისე მუშაობს, როგორც APW საფულის აპლიკაციაში.
secret მხოლოდ სერვერზე უნდა ინახებოდეს. ხელმოწერა ყოველთვის თქვენს backend-ზე ხდება. secret არასდროს ჩადოთ მობილურ აპლიკაციაში ან ბრაუზერის კოდში.
თქვენი აპლიკაცია მიმართავს თქვენს სერვერს, თქვენი სერვერი კი ამ API-ს.
პარტნიორის ავტორიზაცია (HMAC)
ჩვენგან მიიღებთ ორ მნიშვნელობას: Partner ID (მაგ. pk_…) და secret.
secret ერთხელ გადმოგეცემათ. თუ დაიკარგა ან გაჟონა, მოგვმართეთ და ახალს გამოვცემთ. ძველი იმავე წამს წყვეტს მუშაობას.
Header-ები
| Header | მნიშვნელობა |
|---|---|
X-Partner-Id | თქვენი Partner ID |
X-Timestamp | მიმდინარე დრო, unix წამებში. სერვერის დროს ±300 წამზე მეტით არ უნდა სცდებოდეს. |
X-Nonce | შემთხვევითი, ყოველ მოთხოვნაზე უნიკალური სტრიქონი: 16–64 სიმბოლო A-Z a-z 0-9 _ -. მაგალითად UUID. |
X-Client-Ip | საფულის მომხმარებლის (end-user-ის) IP მისამართი. არა თქვენი სერვერის. |
X-Signature | HMAC-SHA256 hex ფორმატში, პატარა ასოებით (იხ. ქვემოთ) |
Content-Type | application/json |
Authorization | Bearer <access_token>. საჭიროა მხოლოდ იმ endpoint-ებზე, რომლებიც „მომხმარებლის token“-ით არის მონიშნული. |
ხელმოსაწერი სტრიქონი
ექვსი ხაზი, ერთმანეთზე \n-ით (LF) გადაბმული. ბოლოს ახალი ხაზი არ ემატება.
POST
/api/v1/auth/login-check
1761140000
3f1c9a0e-5b7d-4e2a-9c61-0d8e2b7f4a10
203.0.113.7
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
- HTTP მეთოდი დიდი ასოებით:
POST. - მისამართის path, დომენისა და query string-ის გარეშე. მაგალითად
/api/v1/auth/login-check. X-Timestamp-ის მნიშვნელობა.X-Nonce-ის მნიშვნელობა.X-Client-Ip-ის მნიშვნელობა.- მოთხოვნის ტანის SHA-256 ჰეში, hex ფორმატში, პატარა ასოებით. ტანი ზუსტად ის ბაიტები უნდა იყოს, რასაც აგზავნით. ცარიელი ტანის ჰეშია
e3b0c442…b855.
X-Signature = hex( HMAC-SHA256( key = secret, message = ხელმოსაწერი სტრიქონი ) )
ჯერ JSON დაასერიალიზეთ, შემდეგ მოაწერეთ ხელი იმ სტრიქონს და ზუსტად იგივე სტრიქონი გაგზავნეთ.
თუ HTTP ბიბლიოთეკა ობიექტს გაგზავნისას ხელახლა გარდაქმნის (ჰარების, ველების რიგის ან რიცხვების ფორმატის შეცვლით), ხელმოწერა არ დაემთხვევა და მიიღებთ შეცდომას 906.
function apwRequest(string $path, array $data, string $clientIp, ?string $customerToken = null): array
{
$partnerId = getenv('APW_PARTNER_ID');
$secret = getenv('APW_SECRET');
$body = json_encode($data ?: new stdClass(), JSON_UNESCAPED_UNICODE);
$timestamp = (string) time();
$nonce = bin2hex(random_bytes(16));
$stringToSign = implode("\n", [
'POST', $path, $timestamp, $nonce, $clientIp, hash('sha256', $body),
]);
$headers = [
'Content-Type: application/json',
'X-Partner-Id: ' . $partnerId,
'X-Timestamp: ' . $timestamp,
'X-Nonce: ' . $nonce,
'X-Client-Ip: ' . $clientIp,
'X-Signature: ' . hash_hmac('sha256', $stringToSign, $secret),
];
if ($customerToken) {
$headers[] = 'Authorization: Bearer ' . $customerToken;
}
$ch = curl_init('https://wallet.apw.ge' . $path);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 140,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
return ['status' => $status, 'body' => json_decode((string) $response, true)];
}
$result = apwRequest('/api/v1/auth/login-check', [
'wallet_number' => '12345678901',
'password' => 'Secret123',
], $_SERVER['REMOTE_ADDR']);const crypto = require('crypto');
async function apwRequest(path, data, clientIp, customerToken) {
const body = JSON.stringify(data ?? {});
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomUUID();
const bodyHash = crypto.createHash('sha256').update(body, 'utf8').digest('hex');
const stringToSign = ['POST', path, timestamp, nonce, clientIp, bodyHash].join('\n');
const signature = crypto.createHmac('sha256', process.env.APW_SECRET)
.update(stringToSign, 'utf8').digest('hex');
const headers = {
'Content-Type': 'application/json',
'X-Partner-Id': process.env.APW_PARTNER_ID,
'X-Timestamp': timestamp,
'X-Nonce': nonce,
'X-Client-Ip': clientIp,
'X-Signature': signature,
};
if (customerToken) headers.Authorization = `Bearer ${customerToken}`;
// body აქ იგივე სტრიქონია, რომელსაც ხელი მოეწერა
const res = await fetch('https://wallet.apw.ge' + path, { method: 'POST', headers, body });
return { status: res.status, body: await res.json() };
}import hashlib, hmac, json, os, time, uuid
import requests
def apw_request(path, data, client_ip, customer_token=None):
body = json.dumps(data or {}, ensure_ascii=False).encode('utf-8')
timestamp = str(int(time.time()))
nonce = uuid.uuid4().hex
string_to_sign = '\n'.join([
'POST', path, timestamp, nonce, client_ip, hashlib.sha256(body).hexdigest(),
])
signature = hmac.new(os.environ['APW_SECRET'].encode(), string_to_sign.encode(), hashlib.sha256).hexdigest()
headers = {
'Content-Type': 'application/json',
'X-Partner-Id': os.environ['APW_PARTNER_ID'],
'X-Timestamp': timestamp,
'X-Nonce': nonce,
'X-Client-Ip': client_ip,
'X-Signature': signature,
}
if customer_token:
headers['Authorization'] = 'Bearer ' + customer_token
# data=body — და არა json=data, რომ გაიგზავნოს ზუსტად ხელმოწერილი ბაიტები
res = requests.post('https://wallet.apw.ge' + path, data=body, headers=headers, timeout=140)
return res.status_code, res.json()PATH_="/api/v1/register/params"
BODY='{}'
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
CLIENT_IP="203.0.113.7"
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')
SIG=$(printf 'POST\n%s\n%s\n%s\n%s\n%s' "$PATH_" "$TS" "$NONCE" "$CLIENT_IP" "$BODY_HASH" \
| openssl dgst -sha256 -hmac "$APW_SECRET" -hex | awk '{print $NF}')
curl -sS "https://wallet.apw.ge$PATH_" \
-H "Content-Type: application/json" \
-H "X-Partner-Id: $APW_PARTNER_ID" \
-H "X-Timestamp: $TS" \
-H "X-Nonce: $NONCE" \
-H "X-Client-Ip: $CLIENT_IP" \
-H "X-Signature: $SIG" \
--data-binary "$BODY"დამატებითი დაცვა
- IP allowlist: თქვენი სერვერ(ებ)ის IP მისამართები მოგვაწოდეთ და მოთხოვნებს მხოლოდ მათგან მივიღებთ.
- Nonce: ერთი და იგივე
X-Nonceმეორედ არ მიიღება (შეცდომა 905). ასე ჩაჭერილი მოთხოვნის გამეორება შეუძლებელია. ხელახლა ცდისას ყოველთვის ახალი nonce და ახალი ხელმოწერა გამოიყენეთ. - დრო: სერვერის საათი NTP-ით სინქრონიზებული გქონდეთ. ±300 წამზე მეტი სხვაობის შემთხვევაში მიიღებთ შეცდომას 904.
მომხმარებლის ავტორიზაცია
access_token სამი endpoint-იდან მოდის: auth/login, register/4 (რეგისტრაციის დასრულება) და password/reset/change. მას Authorization: Bearer <token> header-ში აგზავნით, პარტნიორის HMAC header-ებთან ერთად.
- მოქმედების ვადა 1 საათია. refresh token არ არსებობს. ვადის გასვლის შემდეგ მომხმარებელი თავიდან უნდა შევიდეს.
- ერთ ანგარიშს ერთი აქტიური სესია აქვს. შესვლა ან პაროლის აღდგენა წინა token-ებს აუქმებს, მათ შორის APW-ის საკუთარ აპლიკაციაში. ამიტომ token-ი ნებისმიერ დროს შეიძლება გაუქმდეს და 401 სწორად უნდა დაამუშაოთ.
- არავალიდური ან ვადაგასული token-ის პასუხია HTTP
401ტანით{"message":"Unauthenticated."}. ზოგჯერ ტანია{"errorCode":401,"errorMessage":"Token expired"}. ორივე შემთხვევაში მომხმარებელი შესვლის გვერდზე გადაიყვანეთ. - გამონაკლისი:
billing/pay,transfer/payდაexchange/convertHTTP 401-ს აბრუნებს ტექსტით „ავტორიზაცია მუშავდება“ ან „…ავტორიზაცია დაიბლოკა“. ეს token-ის პრობლემა არ არის: ოპერაცია დამატებით მოწმდება. მომხმარებელს ტექსტი აჩვენეთ და სცადეთ მოგვიანებით. token-ის ნამდვილ პრობლემაზე პასუხი ყოველთვის"Unauthenticated."ან"errorCode":401არის.
პასუხები და შეცდომები
Gateway-ის შეცდომები (9xx)
მოთხოვნა საფულემდე ვერ მივიდა. ფორმატია {"errorCode": 9xx, "errorMessage": "..."}.
| errorCode | HTTP | მიზეზი |
|---|---|---|
| 901 | 400 | header აკლია ან არასწორი ფორმატისაა |
| 902 | 401 | Partner ID უცნობია ან გათიშულია |
| 903 | 403 | მოთხოვნა დაუშვებელი IP მისამართიდან მოვიდა |
| 904 | 401 | X-Timestamp ±300 წამის ფანჯარას სცდება |
| 905 | 401 | X-Nonce უკვე გამოყენებულია |
| 906 | 401 | ხელმოწერა არ ემთხვევა |
| 907 | 429 | წუთში მოთხოვნების ლიმიტი ამოიწურა |
| 908 | 404 | ასეთი endpoint არ არსებობს |
| 910 | 502 | საფულის სერვისი დროებით მიუწვდომელია |
| 911 | 504 | საფულის სერვისმა დროულად არ უპასუხა. მოთხოვნა შეიძლება შესრულდა კიდეც, ამიტომ შედეგი გადაამოწმეთ, სანამ გაიმეორებთ. |
საფულის პასუხები
ხელმოწერის შემოწმების შემდეგ საფულის პასუხი უცვლელად ბრუნდება: სტატუსიც და ტანიც. ტანი ორ ფორმატში მოდის:
| ჯგუფი | წარმატება | შეცდომა |
|---|---|---|
| auth/*, password/reset/*, two-factor/* | HTTP 200, errorCode: 0 | HTTP 200, errorCode ≠ 0 და errorMessage |
| register/*, user/password | HTTP 200 | HTTP 402, {"message": "..."} |
| billing/pay, billing/info, transfer/* | HTTP 200 | HTTP 402, errorCode + errorMessage ან {"message": "..."} |
| user, user/transactions, user/limits, billing კატალოგი | HTTP 200, მონაცემები პირდაპირ (wrapper-ის გარეშე) | 401 / 402 |
| user/services, user/notifications/*, exchange/* | HTTP 200, errorCode: 0 და data | HTTP 402, errorCode + errorMessage (ვალიდაციისას message) |
| verification/*, verification-defect/* | HTTP 200 | HTTP 402, {"message": "..."} |
| requested-document | HTTP 200, errorCode: 0 | HTTP 200, errorCode ≠ 0 |
| qr/verify | HTTP 200, errorCode: 0 | HTTP 401 / 402, errorCode + errorMessage ან {"message": "..."} |
შეცდომის ტექსტი წაიკითხეთ ამ რიგით: errorMessage, მერე message. ტექსტი (errorMessage / message) მომხმარებლისთვის საჩვენებლად არის განკუთვნილი. ის ძირითადად ქართულადაა, ნაწილი ინგლისურად. ლოგიკა ააგეთ errorCode-ზე და HTTP სტატუსზე და არა ტექსტზე.
ლიმიტები
- პარტნიორზე წუთში 600 მოთხოვნა (შეთანხმებით იზრდება). გადაჭარბებისას: 907 / HTTP 429.
- საფულის საკუთარი ლიმიტები. ამის გადაჭარბებისას HTTP 429 ტანით
{"message":"Too Many Attempts."}დაRetry-Afterheader. - SMS კოდის ხელახლა გაგზავნა ერთ ანგარიშზე წუთში ერთხელაა შესაძლებელი.
verification-defect/2ყოველ გამოძახებაზე SMS-ს აგზავნის, ამიტომ ერთ მომხმარებელზე 10 წუთში 5 გამოძახებაა დაშვებული. გადაჭარბებისას: HTTP 429,{"message":"Too Many Attempts."}.- 15 წუთში 10 არასწორი პაროლის შემდეგ ანგარიშზე შესვლა დროებით იბლოკება.
- ერთ token-ზე 5 არასწორი კოდის შემდეგ შესვლის პროცესი თავიდან უნდა დაიწყოს.
- მოთხოვნის timeout თქვენს მხარეს: ჩვეულებრივ endpoint-ებზე მინიმუმ 140 წამი,
billing/pay-ზე,transfer/pay-ზე,exchange/convert-ზე,qr/verify-სა დაverification/2-ზე მინიმუმ 310 წამი. გადახდამდე სისტემა რამდენიმე გარე შემოწმებას აკეთებს და ადრე გაწყვეტილი კავშირი შედეგს არ აუქმებს. - გადახდები (billing) ყოველდღე 23:30-დან 00:10-მდე (თბილისის დროით) მიუწვდომელია:
errorCode 99.
რეგისტრაცია: პროცესი
რეგისტრაცია რამდენიმე ნაბიჯისგან შედგება. ყოველი ნაბიჯი წინას token-ს იყენებს (64-სიმბოლოიანი სტრიქონი; ეს არ არის access_token).
ორი ნაბიჯი მომხმარებლის საკუთარ მოწყობილობაზე სრულდება და API-ზე არ გადის:
- დოკუმენტის სკანირება და სელფი (Identomat);
- ხელშეკრულების ხელმოწერა SMS-ით მიღებულ ბმულზე.
- register/params: სიები ფორმისთვის (ქვეყნები, დასაქმება, შემოსავალი…).
- register/1: კონტაქტი, მისამართი, პაროლი, PEP სტატუსი. აბრუნებს
token-ს. - register/2: ეკონომიკური პროფილი. აბრუნებს
iframe_url-ს. - მომხმარებელი
iframe_url-ს თავის მოწყობილობაზე ხსნის (კამერა საჭიროა) და დოკუმენტს და სელფის ასრულებს. - register/3: ვამოწმებთ დოკუმენტს და მომხმარებელს ორი SMS მიდის: ხელშეკრულების ბმული და 6-ნიშნა კოდი.
- მომხმარებელი ხელშეკრულებას ბმულზე აწერს ხელს. ბმული 10 წუთი მოქმედებს.
- register/check: გამოკითხეთ, სანამ
status: 1არ დაბრუნდება. თუ ბმულს ვადა გაუვიდა, გამოიყენეთ register/contract-sms. - register/4: SMS კოდით სრულდება რეგისტრაცია. აბრუნებს
access_token-ს.
შეზღუდვები:
- რეგისტრაცია ამჟამად მხოლოდ საქართველოს მოქალაქეებისთვისაა.
- მომხმარებელი 18 წელს უნდა იყოს მიღწეული.
- დოკუმენტად მიიღება პირადობის მოწმობა ან პასპორტი.
POST/api/v1/register/params
ფორმის ველების დასაშვები მნიშვნელობები. ტანი ცარიელია: {}.
{
"message": "Success",
"data": {
"0": {
"countrie": [{"ccode": "GE", "country": "Georgia", "code": "995", ...}],
"sferos": [...],
"userEmployeeStatus": [...],
"userExpectedTurnover": [...],
"userMonthlyIncome": [...],
"userPurposeRelationship": [...],
"userSourceOfIncome": [...],
"currency_id": [{"id": 981, "name": "GEL"}, {"id": 978, "name": "EUR"}, {"id": 840, "name": "USD"}, {"id": 643, "name": "RUB"}]
},
"links": {"contract": "https://…pdf", "privacy_policy": "https://…pdf", "limits": "https://…pdf"},
"pep_status": [...], "pep_family_status": [...],
"pep_definition": "...", "pep_family_definition": "..."
}
}
სიები data["0"]-ის ქვეშაა (გასაღები სტრიქონი "0"-ია).
POST/api/v1/register/1
| ველი | წესი |
|---|---|
mobile | სავალდებულო. 9–15 ციფრი, ქვეყნის კოდით (995555123456). უნიკალური უნდა იყოს. |
email | სავალდებულო. ვალიდური და უნიკალური ელ-ფოსტა. |
legal_address | სავალდებულო. 3–255 სიმბოლო. |
address_same | სავალდებულო. 1: ფაქტიური მისამართი იურიდიულს ემთხვევა; 0: არ ემთხვევა. |
real_address | სავალდებულოა, თუ address_same = 0. 3–255 სიმბოლო. |
password | სავალდებულო. მინიმუმ 8 სიმბოლო, ასოები და ციფრები ერთად. |
confirm_password | სავალდებულო. password-ს უნდა ემთხვეოდეს. |
pep_status | სავალდებულო. 0 ან 1: არის თუ არა პოლიტიკურად აქტიური პირი. |
pep_title | სავალდებულოა, თუ pep_status = 1. 3–255 სიმბოლო. |
pep_family_status | სავალდებულო. 0 ან 1. |
pep_family | სავალდებულოა, თუ pep_family_status = 1. 3–255 სიმბოლო. |
limits, privacy_policy, contract | სავალდებულო. სამივე 1 უნდა იყოს: მომხმარებელი დაეთანხმა links-ში მოცემულ დოკუმენტებს. |
// 200
{"token": "Xr9…64 სიმბოლო", "message": "Success"}
// 402
{"message": "ელ-ფოსტა უკვე გამოყენებულია"}
POST/api/v1/register/2
| ველი | წესი |
|---|---|
token | register/1-ის token |
dual_citizen | 1: ორმაგი მოქალაქეობა აქვს; 2: არ აქვს |
country2 | სავალდებულოა, თუ dual_citizen = 1. ქვეყნის 2-ასოიანი კოდი (ccode). |
employee_status | ID userEmployeeStatus-დან |
job_title, occupied_position | 3–100 სიმბოლო. ორივე სავალდებულოა, როცა employee_status = 1. როცა = 2, მხოლოდ occupied_position. |
source_of_income_id | სავალდებულოა, თუ employee_status = 3. ID userSourceOfIncome-დან. |
company_name, company_country | სავალდებულოა, თუ employee_status არის 4 ან 5. company_country 2-ასოიანი კოდია. |
monthly_income | ID userMonthlyIncome-დან |
expected_turnover | ID userExpectedTurnover-დან |
purpose_id | ID userPurposeRelationship-დან |
currencies | მძიმით გამოყოფილი ვალუტები 981,840,978,643-დან, მაგ. "981,840" |
// 200
{"token": "…", "iframe_url": "https://widget.identomat.com/?session_token=…", "message": "Success"}
iframe_url მომხმარებელს გაუხსენით: WebView-ში კამერის ნებართვით ან ბრაუზერში. როცა მომხმარებელი სკანირებას დაასრულებს, გამოიძახეთ register/3.
POST/api/v1/register/3
ველი: token.
ვამოწმებთ Identomat-ის შედეგს, დოკუმენტის ვალიდურობას და ასაკს. წარმატების შემთხვევაში მომხმარებელს ორი SMS მიდის: ხელშეკრულების ბმული და 6-ნიშნა კოდი register/4-ისთვის. ეს ნაბიჯი რამდენიმე წამი გრძელდება.
// 200
{"token": "…", "mobile": "995******123", "expire": 5, "message": "Success"}
// 402: მაგალითები
{"message": "user_checking"} // დოკუმენტი ხელით მოწმდება, სცადეთ მოგვიანებით
{"message": "user must be 18 years or older!"}
{"message": "არარეზიდენტების რეგისტრაცია დროებით შეზღუდულია!"}
POST/api/v1/register/check
ველი: token. ამოწმებს, მოაწერა თუ არა მომხმარებელმა ხელშეკრულებას ხელი. გამოკითხეთ რამდენიმე წამში ერთხელ.
// 200: ხელმოწერილია
{"status": 1, "message": "ხელმოწერილი"}
// 402: ჯერ ხელმოუწერელია. ეს ნორმალური მდგომარეობაა და არა შეცდომა.
{"status": 0, "message": "ხელმოუწერელი"}
POST/api/v1/register/contract-sms
ველი: token. ხელშეკრულების ბმულს ხელახლა აგზავნის. გამოიძახეთ მხოლოდ მაშინ, როცა წინა ბმულს ვადა გაუვიდა, ანუ გაგზავნიდან 10 წუთის შემდეგ.
// 200
{"token": "…", "mobile": "99*****23", "expire": 5, "message": "Success"}
POST/api/v1/register/4
| ველი | წესი |
|---|---|
token | register/3-ის token |
sms | 6 ციფრი: კოდი register/3-ის SMS-დან |
// 200
{
"message": "რეგისტრაცია წარმატებით დასრულდა",
"user": {"id": 1, "verify_id": 1, "iban": "GE…", "wallet_number": "12345678901",
"first_name": "…", "last_name": "…", "birth_date": "1990-01-01",
"balance": 0, "balance_usd": 0, "balance_eur": 0, "balance_rub": 0,
"mobile": "995…", "email": "…"},
"access_token": "eyJ0eXAiOiJKV1Qi…"
}
// 402
{"message": "ხელშეკრულებაზე დათანხმება აუცილებელია!"}
შესვლა: პროცესი
- auth/login-check: საფულის ნომერი და პაროლი. პასუხის
two_factorველი გეუბნებათ, რომელი კოდია საჭირო. two_factor: "sms": მომხმარებელს SMS კოდი მიუვა. ხელახლა გაგზავნისთვის გამოიყენეთ auth/login-sms.
two_factor: "google": კოდი მომხმარებლის Authenticator აპლიკაციაშია. SMS არ იგზავნება.- auth/login: token და კოდი. აბრუნებს
access_token-ს.
იურიდიული პირი (type = 2): ერთ ფიზიკურ პირს რამდენიმე კომპანია შეიძლება ჰქონდეს მიბმული. auth/login-check აბრუნებს legal_entities სიას; თუ მასში ერთზე მეტი ჩანაწერია, auth/login-ს უნდა გადასცეთ legal_user_id. ერთი კომპანიის შემთხვევაში არაფერი იცვლება.
POST/api/v1/auth/login-check
| ველი | წესი |
|---|---|
wallet_number | სავალდებულო. 11 ციფრი. |
password | სავალდებულო |
type | არასავალდებულო. 1: ფიზიკური პირი (ნაგულისხმევი); 2: შესვლა იმ იურიდიული პირის სახელით, რომელსაც მომხმარებელი მართავს. |
// SMS
{"two_factor": "sms", "phone": "995******123", "token": "…", "date": "2026-10-22 12:00:00",
"expire": 1, "errorCode": 0, "message": "Sms send success"}
// Authenticator
{"two_factor": "google", "token": "…", "date": "…", "expire": 5, "errorCode": 0,
"message": "Authenticator code required"}
expire არის კოდის მოქმედების ვადა წუთებში.
type = 2-ზე პასუხს ემატება legal_entities — იმ კომპანიების სია, რომლითაც ამ მომხმარებელს შესვლა შეუძლია. ფიზიკური შესვლის პასუხში ეს ველი არ არის.
{"two_factor": "sms", "phone": "995******123", "token": "…", "expire": 1,
"errorCode": 0, "message": "Sms send success",
"legal_entities": [
{"legal_user_id": 12, "wallet_number": "00000000123",
"name": "შპს ალფა", "identification_number": "400147211"},
{"legal_user_id": 19, "wallet_number": "00000000456",
"name": "შპს ბეტა", "identification_number": "405123456"}
]}
სიაში მხოლოდ ის კომპანიები ხვდება, რომლითაც შესვლა ამ მომენტში დაშვებულია — ვადაგასული ან შეჩერებული უფლებამოსილება და დაბლოკილი კომპანია გამორიცხულია. name კომპანიის დასახელებაა, identification_number — საიდენტიფიკაციო კოდი; ორივე მომხმარებლისთვის საჩვენებელია, ხოლო auth/login-ს legal_user_id გადაეცემა.
| errorCode | მნიშვნელობა |
|---|---|
| 1 | ვალიდაციის შეცდომა |
| 2, 4 | საფულის ნომერი ან პაროლი არასწორია, ან ცდების რაოდენობა ამოიწურა |
| 3 | ავტორიზაცია დამატებით მოწმდება ან დაბლოკილია. ტექსტი აჩვენეთ მომხმარებელს და მოგვიანებით სცადეთ. |
| 5 | SMS ახლახან გაიგზავნა. სცადეთ 1 წუთში. |
| 6 | იურიდიული პირი ვერ მოიძებნა (type = 2) |
| 8 | კომპანია მიბმულია, მაგრამ ამ მომენტში არცერთით შესვლა არ შეიძლება (type = 2): მინდობილობის ვადა ამოიწურა, არ არის მითითებული, ჯერ არ დაწყებულა, ან უფლებამოსილება შეჩერებული/გაუქმებულია. ფიზიკური პირით შესვლა კი შესაძლებელია. |
POST/api/v1/auth/login-sms
ველი: token (login-check-იდან). SMS კოდს ხელახლა აგზავნის, წუთში ერთხელ. token არ იცვლება.
{"phone": "995******123", "token": "…", "date": "…", "expire": 1, "errorCode": 0, "errorMessage": "Sms send success"}
თუ errorCode: 6 დაბრუნდა, მომხმარებელი Authenticator აპლიკაციას იყენებს და SMS არ იგზავნება.
POST/api/v1/auth/login
| ველი | წესი |
|---|---|
token | login-check-ის token |
sms | 6-ნიშნა SMS კოდი. 1 წუთი მოქმედებს. |
code | 6-ნიშნა Authenticator კოდი, როცა two_factor: "google". login-check-იდან 5 წუთის განმავლობაში უნდა გამოიყენოთ. |
legal_user_id | არასავალდებულო. რომელი იურიდიული პირით ხდება შესვლა — login-check-ის legal_entities-იდან. სავალდებულოა მხოლოდ მაშინ, როცა სიაში ერთზე მეტი ჩანაწერია; ერთის შემთხვევაში გამოტოვეთ. |
{
"user": {"id": 1, "verify_id": 1, "iban": "GE…", "wallet_number": "12345678901",
"first_name": "…", "last_name": "…", "birth_date": "…", "mobile": "…", "email": "…",
"balance": 10.5, "balance_usd": 0, "balance_eur": 0, "balance_rub": 0,
"frozen_balance": 0, "frozen_balance_usd": 0, "frozen_balance_eur": 0, "frozen_balance_rub": 0,
"type": 1, "verification_defect": 0, "requested_document": 0, ...},
"access_token": "eyJ0eXAiOiJKV1Qi…",
"errorCode": 0,
"errorMessage": "success"
}
| errorCode | მნიშვნელობა |
|---|---|
| 1 | ვალიდაციის შეცდომა |
| 2 | კოდი არასწორია ან ვადაგასულია, ან ცდები ამოიწურა. ბოლო შემთხვევაში შესვლა login-check-იდან თავიდან დაიწყეთ. |
| 5 | იურიდიული პირი ვერ მოიძებნა |
| 7 | Authenticator კოდის ცდები ამოიწურა |
| 8 | უფლებამოსილება შეწყდა login-check-ის შემდეგ (იხ. login-check, კოდი 8) |
| 9 | აირჩიეთ იურიდიული პირი: legal_user_id არ გამოგზავნეთ და სიაში ერთზე მეტი კომპანიაა, ან გამოგზავნილი id ამ მომხმარებელს არ ეკუთვნის. პასუხს თან ახლავს legal_entities. |
კოდი 9-ზე token ძალაში რჩება — აჩვენეთ არჩევანი და იმავე token-ითა და კოდით ხელახლა დაუძახეთ. შესვლა თავიდან არ იწყება.
// 200 — აირჩიეთ კომპანია
{"errorCode": 9, "errorMessage": "აირჩიეთ იურიდიული პირი",
"legal_entities": [
{"legal_user_id": 12, "wallet_number": "00000000123",
"name": "შპს ალფა", "identification_number": "400147211"},
{"legal_user_id": 19, "wallet_number": "00000000456",
"name": "შპს ბეტა", "identification_number": "405123456"}
]}
წარმატებული შესვლა ამ ანგარიშის ყველა სხვა სესიას აუქმებს. იურიდიული პირისთვის ეს იმასაც ნიშნავს, რომ ერთი კომპანიის ორი უფლებამოსილი პირი ერთდროულად ვერ იქნება შესული — მეორის შესვლა პირველს გამორთავს.
POST/api/v1/auth/logoutმომხმარებლის token
ტანი ცარიელია. აუქმებს მომხმარებლის token-ებს.
{"errorCode": 0, "errorMessage": "success"}
პაროლის აღდგენა: პროცესი
- password/reset/check: საფულის ნომერი. მომხმარებელს SMS კოდი მიუვა.
- password/reset/verify: კოდი. აბრუნებს ახალ token-ს.
- password/reset/change: ახალი პაროლი, ახალი token-ით, 10 წუთის განმავლობაში. მომხმარებელი პირდაპირ შედის სისტემაში.
უცნობ საფულის ნომერზე password/reset/check-იც წარმატებას აბრუნებს. ეს განზრახ არის ასე, რომ API-ით ვერ გაირკვეს, არსებობს თუ არა საფულე. ასეთ შემთხვევაში შემდეგი ნაბიჯი დააბრუნებს „არასწორ კოდს“.
POST/api/v1/password/reset/check
ველი: wallet_number (11 ციფრი).
{"phone": "995******123", "token": "…", "date": "…", "expire": 1, "errorCode": 0,
"errorMessage": "Password reset sms send success"}
შეცდომები: 1 ვალიდაცია · 3 ავტორიზაცია მოწმდება ან დაბლოკილია · 4 SMS ახლახან გაიგზავნა.
POST/api/v1/password/reset/sms
ველი: token. SMS-ს ხელახლა აგზავნის, წუთში ერთხელ. პასუხის ფორმატი reset/check-ისას ემთხვევა.
POST/api/v1/password/reset/verify
| ველი | წესი |
|---|---|
token | reset/check-ის token |
sms | 6 ციფრი. 1 წუთი მოქმედებს. |
{"token": "…ახალი token…", "date": "…", "errorCode": 0, "errorMessage": "SMS check success"}
შეცდომები: 1 ვალიდაცია · 2 კოდი არასწორია ან ცდები ამოიწურა · 3 კოდს ვადა გაუვიდა.
POST/api/v1/password/reset/change
| ველი | წესი |
|---|---|
token | reset/verify-ის ახალი token |
password | მინიმუმ 8 სიმბოლო, ასოები და ციფრები ერთად |
confirm_password | password-ს უნდა ემთხვეოდეს |
წარმატების პასუხი auth/login-ისას ემთხვევა: user და access_token. შეცდომები: 1 ვალიდაცია · 2 token არასწორია ან უკვე გამოყენებულია · 3 token-ს ვადა გაუვიდა (10 წუთი).
გადახდები: პროცესი
მომხმარებლის საფულიდან სერვისების გადახდა: მობილური, კომუნალური, ინტერნეტი და სხვ. კატალოგი საჯაროა (მომხმარებლის token არ სჭირდება), გადახდას კი token სჭირდება.
- billing/categories → billing/category/{id} → billing/service/{id}: სერვისის არჩევა.
serviceშეიცავს ველების აღწერას (params_info,params_pay), თანხის ზღვრებს და საკომისიოს. - billing/info: აბონენტის შემოწმება (დავალიანება, სახელი…). პასუხის
smsველი გეუბნებათ, სჭირდება თუ არა გადახდას SMS კოდი. - თუ
sms = 1: billing/pay-sms. კოდი 2 წუთი მოქმედებს. - billing/pay: გადახდა. წარმატებისას მიიღებთ
operationId-ს. - billing/status/{operationId}: გამოკითხეთ, სანამ სტატუსი
3(შესრულებული) ან4(გაუქმებული) არ გახდება.
გადახდა ასინქრონულია. billing/pay-ის წარმატება ნიშნავს, რომ გადახდა მიღებულია. თანხა ამ მომენტში იბლოკება საფულეზე, ჩამოიჭრება კი შესრულებისას, ჩვეულებრივ რამდენიმე წამში. საბოლოო შედეგი billing/status-ით შეამოწმეთ.
თუ პასუხი „ოპერაცია მუშავდება…“ ან 911 / timeout მიიღეთ, გადახდა არ გაიმეოროთ. შედეგი უცნობია და გადახდა შეიძლება უკვე შესრულდა. შეამოწმეთ user/transactions: ჩანაწერი იქ „მიმდინარე: …“ სახით გამოჩნდება. გამეორება ორმაგ გადახდას გამოიწვევს.
ვალუტა ყოველთვის ლარია (GEL). ერთი და იგივე გადახდა (იგივე სერვისი, აბონენტი და თანხა) 20 წამის განმავლობაში მეორედ არ მიიღება.
კატალოგი
POST/api/v1/billing/categories: კატეგორიების მასივი.
[{"id": 32, "image": "https://uploads.allpayway.ge/files/categories/….png", "count": 3,
"lang": {"ka": "მობილური", "en": "Mobile", "ru": "Мобильная связь"}}, ...]
POST/api/v1/billing/category/{id}: კატეგორიის სერვისები.
{"services": [{"id": 19, "name": "Magti", "lang": {...}, "image": "…", "min_amount": "1.00", "max_amount": "400.00", ...}],
"category": {"lang": {"ka": "…", "en": "…", "ru": "…"}}}
POST/api/v1/billing/services: ყველა სერვისი ერთ მასივად.
POST/api/v1/billing/service/{id}: ერთი სერვისის სრული აღწერა.
{
"errorCode": 1000,
"service": {
"id": 19, "name": "Magti", "lang": {"ka": "მაგთი", "en": "Magti", "ru": "Магти"},
"currency_id": 981, "min_amount": "1.00", "max_amount": "400.00", "category_id": 32,
"image": "https://uploads.allpayway.ge/files/services/….png",
"params_info": [
{"name": "phone_number", "regexp": "/^(\\d{9})$/i", "description": "ტელეფონის ნომერი", "example": "599470076"}
],
"params_pay": [
{"name": "phone_number", "regexp": "/^(\\d{9})$/i", "description": "ტელეფონის ნომერი", "example": "599470076"}
],
"commission": {
"client_commission_percent": "4.00", "client_commission_fixed": "0.00",
"min_client_commission": "0.000000", "max_client_commission": "0.000000",
"min_amount": "1.000000", "max_amount": "1000.000000", "rate": 1
}
}
}
params_info: billing/info-ის ველები.params_pay: billing/pay-ის ველები. თითოეული ველის სახელი (name) მოთხოვნის ველის სახელია. მნიშვნელობაregexp-ს უნდა აკმაყოფილებდეს.descriptionდაexampleფორმაში გამოიყენეთ.commission: მომხმარებლის საკომისიო (პროცენტი, ფიქსირებული, მინიმუმი და მაქსიმუმი). საბოლოო საკომისიო გადახდის პასუხში და სტატუსში ბრუნდება.
POST/api/v1/billing/param: ერთი ველის აღწერა. ტანი: {"param": "phone_number"}.
POST/api/v1/billing/info
აბონენტის შემოწმება. ველები: service_id და სერვისის ყოველი params_info ველი.
// მოთხოვნა
{"service_id": 19, "phone_number": "599470076"}
// 200: ველები სერვისზეა დამოკიდებული. „sms“ ყოველთვის არის.
{"errorCode": 1000, "errorMessage": "წარმატებული", ..., "sms": 1}
// 402
{"message": "The phone number field is required."}
{"errorCode": 99, "errorMessage": "00:10 საათამდე გადახდას ვერ შეძლებთ"}
POST/api/v1/billing/pay-smsმომხმარებლის token
მომხმარებელს გადახდის დასადასტურებელი 6-ნიშნა კოდი მიუვა. კოდი 2 წუთი მოქმედებს. ტანი ცარიელია.
{"message": "Success"}
მომხმარებელს ერთდროულად ერთი აქტიური SMS კოდი აქვს. ის საერთოა გადახდისთვის, გადარიცხვისთვის, შესვლისა და verification-defect/2-ისთვის. ყოველი ახალი გაგზავნა წინა კოდს აუქმებს. კოდი მოითხოვეთ უშუალოდ pay-ის წინ.
POST/api/v1/billing/payმომხმარებლის token
| ველი | წესი |
|---|---|
service_id | სერვისის ID |
სერვისის params_pay ველები | თითოეული თავისი regexp-ით |
amount | თანხა ლარში, მაქსიმუმ 2 ათწილადით და 0-ზე მეტი ("10", "10.50"). სერვისის min_amount/max_amount ფარგლებში. |
sms | 6-ნიშნა კოდი, თუ billing/info-მ sms: 1 დააბრუნა |
// მოთხოვნა
{"service_id": 19, "phone_number": "599470076", "amount": "10.00", "sms": "123456"}
// 200: გადახდა მიღებულია
{"errorCode": 1000, "errorMessage": "წარმატებული", "operationId": 987654,
"accoutant": {"genAmount": 10.4, "clientCommission": 0.4}, ...}
შეცდომები (HTTP 402):
| პასუხი | მნიშვნელობა |
|---|---|
errorCode 9 | გადახდა უარყოფილია: ბალანსი არ კმარა, ლიმიტი ამოიწურა, SMS კოდი არასწორია ან ვადაგასულია, მომხმარებელი არ არის ვერიფიცირებული, ან იგივე გადახდა ახლახან გაიგზავნა. მიზეზი errorMessage-შია. |
errorCode 9 + „ოპერაცია მუშავდება…“ | შედეგი უცნობია. არ გაიმეოროთ. შეამოწმეთ user/transactions. |
errorCode 8 | მომხმარებლის პირადობის დოკუმენტს ვადა გაუვიდა. საჭიროა განახლება. |
errorCode 99 | ღამის შესვენება, 23:30–00:10 |
სხვა errorCode | პროვაიდერმა უარყო. თანხა არ ჩამოიჭრა. |
{"message": "..."} | ველის ვალიდაცია ან დოკუმენტის შემოწმების შეცდომა |
| HTTP 401 „ავტორიზაცია მუშავდება“ | დამატებითი შემოწმება მიმდინარეობს. სცადეთ მოგვიანებით. SMS კოდი 2 წუთის განმავლობაში ისევ მოქმედებს. |
POST/api/v1/billing/status/{operationId}მომხმარებლის token
operationId billing/pay-ის პასუხიდან. ტანი ცარიელია. პასუხი ყოველთვის HTTP 200-ია.
{"errorCode": 0, "errorMessage": "success", "data": {
"service": {"image": "…", "lang": {"ka": "მაგთი", "en": "Magti", "ru": "Магти"},
"abonent": "599470076", "amount": "10.00", "gen_amount": "10.40", "client_comision": "0.40"},
"status": {"status_id": 3, "description": "შესრულებული"}}}
| status_id | მნიშვნელობა | რა ვქნათ |
|---|---|---|
| 1 | რეგისტრირებული | გამოკითხეთ ისევ |
| 2 | მიმდინარე | გამოკითხეთ ისევ |
| 3 | შესრულებული | საბოლოოა: თანხა ჩამოიჭრა |
| 4 | გაუქმებული | საბოლოოა: თანხა განიბლოკა |
| 5 | დასადასტურებელი | ხელით მუშავდება, მოგვმართეთ |
გადახდა თუ ვერ მოიძებნა, service და status ცარიელი მასივებია ([]).
გამოკითხეთ 5–10 წამში ერთხელ.
გადარიცხვები: პროცესი
APW საფულიდან APW საფულეზე, მყისიერად. ყველა endpoint მომხმარებლის token-ს მოითხოვს.
- transfer/info: მიმღების შემოწმება (საფულის ნომრით ან IBAN-ით) და საკომისიო. არასავალდებულოა.
- transfer/pay-sms: დასადასტურებელი კოდი SMS-ით. 2 წუთი მოქმედებს.
- transfer/pay: გადარიცხვა.
POST/api/v1/transfer/infoმომხმარებლის token
| ველი | წესი |
|---|---|
type | 1: საფულის ნომრით; 2: IBAN-ით |
wallet_number | 11 ციფრი (როცა type = 1) |
iban | GE00DL0000000000000000 ფორმატით (როცა type = 2) |
// 200
{"errorCode": 0, "errorMessage": "Success",
"data": {"reciver": "გ. ბ.", "iban": "GE00DL0000000000000000", "percents": ...}}
reciver: მიმღების ინიციალები, რომ მომხმარებელმა გადაამოწმოს. percents: გადარიცხვის საკომისიო.
შეცდომები (402): 1 ვალიდაცია · 2 მომსახურება შეზღუდულია · 3 მიმღები ვერ მოიძებნა · 4 საკუთარ საფულეზე გადარიცხვა · 22 დროებითი ტექნიკური შეფერხება.
POST/api/v1/transfer/pay-smsმომხმარებლის token
billing/pay-sms-ის ანალოგიური: 6-ნიშნა კოდი 2 წუთის ვადით და ის იგივე საერთო კოდია (იხ. შენიშვნა). პასუხი: {"message": "Success"}.
POST/api/v1/transfer/payმომხმარებლის token
| ველი | წესი |
|---|---|
type, wallet_number / iban | როგორც transfer/info-ში |
amount | მაქსიმუმ 2 ათწილადით ("25.50") |
currency_id | 981 GEL · 840 USD · 978 EUR · 643 RUB |
destination | გადარიცხვის დანიშნულება (ტექსტი) |
sms | 6-ნიშნა კოდი transfer/pay-sms-დან |
// მოთხოვნა
{"type": 1, "wallet_number": "12345678901", "amount": "25.50", "currency_id": 981,
"destination": "ვალის დაბრუნება", "sms": "123456"}
// 200: გადარიცხვა შესრულდა
{"errorCode": 0, "errorMessage": "Success", "data": {...}}
შეცდომები (HTTP 402, errorCode):
| errorCode | მნიშვნელობა |
|---|---|
| 1 | ვალიდაცია |
| 2–9 | გამგზავნის შემოწმება ვერ გაიარა: შეზღუდვა, დოკუმენტი, ლიმიტი (9) |
| 10–18 | მიმღების შემოწმება ვერ გაიარა |
| 19 | ბალანსი არ კმარა |
| 20 | SMS კოდი არასწორია |
| 21 | SMS კოდს ვადა გაუვიდა |
| 22 | შედეგი უცნობია (გადარიცხვის სერვისმა არ უპასუხა). არ გაიმეოროთ, ჯერ user/transactions შეამოწმეთ. |
| HTTP 401 „ავტორიზაცია მუშავდება“ | დამატებითი შემოწმება. სცადეთ მოგვიანებით. |
მომხმარებელი
POST/api/v1/userმომხმარებლის token
მომხმარებლის მიმდინარე მონაცემები და ბალანსები. ტანი ცარიელია. პასუხი ობიექტია wrapper-ის გარეშე:
{"id": 1, "iban": "GE…", "wallet_number": "12345678901", "first_name": "…", "last_name": "…",
"birth_date": "…", "mobile": "…", "email": "…",
"balance": 10.5, "balance_usd": 0, "balance_eur": 0, "balance_rub": 0,
"frozen_balance": 0, "frozen_balance_usd": 0, "frozen_balance_eur": 0, "frozen_balance_rub": 0,
"avatar": null, "verify_id": 1, "type": 1,
"verification_defect": 0, "requested_document": 0}
POST/api/v1/user/transactionsმომხმარებლის token
ოპერაციების ისტორია, ახლიდან ძველისკენ. ყველა ფილტრი არასავალდებულოა. ველი, რომელსაც არ იყენებთ, საერთოდ არ გაგზავნოთ (ცარიელი სტრიქონი ვალიდაციის შეცდომას იძლევა).
| ველი | წესი |
|---|---|
from_date, to_date | Y-m-d, ორივე დღის ჩათვლით |
from_amount, to_amount | თანხის დიაპაზონი |
currency_id | 981 / 840 / 978 / 643 |
limit | ჩანაწერების რაოდენობა, ნაგულისხმევად 10. გთხოვთ, 100-ზე მეტს ნუ მოითხოვთ. |
[{"id": 1201, "date": "2026-10-22 12:00:05", "description": "Magti: 599470076",
"amount": 10.4, "type": 0, "balance": 89.6, "currency_id": 981, "currency": "GEL",
"service_id": 19, "abonent": "599470076", "gen_amount": "10.40", "client_comision": "0.40", "status_id": 3}, ...]
type:1შემოსავალი,0გასავალი.- დაუსრულებელი გადახდები „მიმდინარე: …“-ით იწყება, გაუქმებულები „გაუქმებული ოპერაცია: …“-ით. მათი
balanceარისnull. idსხვადასხვა ცხრილიდან მოდის და ისტორიაში უნიკალური არ არის. ჩანაწერის გასაღებად არ გამოიყენოთ.
POST/api/v1/user/passwordმომხმარებლის token
| ველი | წესი |
|---|---|
old_password | მიმდინარე პაროლი |
new_password | მინიმუმ 8 სიმბოლო, ასოები და ციფრები ერთად |
confirm_password | new_password-ს უნდა ემთხვეოდეს |
// 200
{"message": "პაროლი წარმატებით შეიცვალა"}
// 402
{"message": "ძველი პაროლი არასწორია!"}
POST/api/v1/user/language/{locale}მომხმარებლის token
locale: ge, en ან ru. ინახავს მომხმარებლის სასურველ ენას (გამოიყენება გადახდის გვერდებზე). ტანი ცარიელია.
{"message": "success"}
POST/api/v1/user/limitsმომხმარებლის token
მომხმარებლის ხარჯვის ლიმიტები ლარში: თვიური და დღიური. ტანი ცარიელია. პასუხი wrapper-ის გარეშეა.
// ფიზიკური პირი
{"month": "5000.00", "day": "1500.00"}
// იურიდიული პირი
{"month": "unlimited", "day": "unlimited"}
ორივე ველი სტრიქონად წაიკითხეთ: ის რიცხვიცაა და "unlimited"-იც.
POST/api/v1/user/servicesმომხმარებლის token
საფულით გადასახდელი სერვისები, კატეგორიებად დაჯგუფებული, თანხის ზღვრებითა და მომხმარებლის საკომისიოთი. ტანი ცარიელია. სერვისის სრული აღწერისთვის (ველები, ლოგო, სახელები ენებზე) გამოიყენეთ billing/service/{id}.
{"errorCode": 0, "errorMessage": "success", "data": [
{"category_id": 32, "services": [
{"service_id": 19, "name": "Magti", "min_amount": 1.0, "max_amount": 400.0,
"client_commission_percent": 4.0, "client_commission_fixed": 0.0,
"min_client_commission": 0.0, "max_client_commission": 0.0}, ...]}, ...]}
ჩანაწერები თუ არ არის: HTTP 402, {"errorCode": 1, "errorMessage": "ჩანაწერები ვერ მოიძებნა"}.
POST/api/v1/user/kycმომხმარებლის token
მომხმარებლის KYC დოკუმენტები (ანკეტა და მისი დადასტურება). ტანი ცარიელია.
{"errorCode": 0, "errorMessage": "success", "data": [
{"id": 123, "file": "https://…/files/kyc/…?expires=…&sig=…", "date": "2026-10-22T10:00:00.000000Z"}, ...]}
file ხელმოწერილი ბმულია და 1 საათი მოქმედებს. ბმული არ შეინახოთ: საჭიროებისას ხელახლა გამოიძახეთ. ეს პირადი დოკუმენტებია, მომხმარებლის გარდა არავის აჩვენოთ. დოკუმენტები თუ არ არის, data ცარიელი მასივია.
შეტყობინებებიმომხმარებლის token
APW-ის შეტყობინებები მომხმარებლისთვის. ყველა endpoint-ის ტანი ცარიელია. შეტყობინების ფორმატი:
{"id": 5, "user_id": 42, "type_id": 1, "seen": 0, "seen_at": null,
"title": "…", "text": "…", "created_at": "…", "updated_at": "…"}
| Endpoint | რას აბრუნებს |
|---|---|
/api/v1/user/notifications/next | ერთ წაუკითხავ შეტყობინებას data-ში. თუ ასეთი არ არის, data არის null. რიგი გარანტირებული არ არის. |
/api/v1/user/notifications/new | ყველა წაუკითხავს, მასივად |
/api/v1/user/notifications/all/{limit} | ბოლო limit შეტყობინებას, ახლიდან ძველისკენ, წაკითხულების ჩათვლით. limit: 1–100. |
/api/v1/user/notifications/seen/{id} | შეტყობინებას წაკითხულად ნიშნავს |
{"errorCode": 0, "errorMessage": "success", "data": [ … ]}
seen/{id} ყოველთვის {"errorCode": 0, "errorMessage": "success"}-ს აბრუნებს, მაშინაც, როცა ასეთი შეტყობინება არ არსებობს ან სხვა მომხმარებელს ეკუთვნის (სხვისი შეტყობინება არ იცვლება). next შეტყობინებას წაკითხულად არ ნიშნავს.
ორფაქტორიანი ავტორიზაცია (Authenticator)მომხმარებლის token
ნაგულისხმევად შესვლის კოდი SMS-ით მოდის. მომხმარებელს შეუძლია Google Authenticator ან სხვა TOTP აპლიკაცია დააკავშიროს.
ყველა endpoint აბრუნებს HTTP 200-ს. წარმატებისას: {"errorCode": 0, "errorMessage": "success", "data": {...}}.
მიმდინარე მდგომარეობა (data):
{"method": "sms" | "google", "method_id": 1 | 2, "google_enrolled": true,
"google_confirmed_at": "2026-10-22 12:00:00" | null, "google_setup_pending": false}
| Endpoint | ველები | რას აკეთებს |
|---|---|---|
/api/v1/two-factor | — | აბრუნებს მიმდინარე მდგომარეობას |
/api/v1/two-factor/google/setup | — | იწყებს დაკავშირებას. data: secret, otpauth_uri, digits, period. otpauth_uri QR კოდად აჩვენეთ. |
/api/v1/two-factor/google/confirm | code (6 ციფრი, აპლიკაციიდან) | ადასტურებს დაკავშირებას. ამის შემდეგ შესვლა Authenticator-ის კოდს მოითხოვს. |
/api/v1/two-factor/google/cancel | — | აუქმებს დაუსრულებელ დაკავშირებას |
/api/v1/two-factor/google/disable | code | აპლიკაციას თიშავს და შესვლა SMS-ზე ბრუნდება |
/api/v1/two-factor/method | method: sms ან google; code, თუ google-იდან sms-ზე გადადის | ცვლის შესვლის მეთოდს |
შეცდომები: 1 ვალიდაცია · 2 კოდი არასწორია ან ვადაგასულია · 3 აპლიკაცია არ არის დაკავშირებული.
ვალუტა
ვალუტის კურსი და გადაცვლა საფულის ბალანსებს შორის. ყველა endpoint მომხმარებლის token-ს მოითხოვს.
POST/api/v1/exchange/currenciesმომხმარებლის token
ტანი ცარიელია.
{"errorCode": 0, "errorMessage": "Success", "data": [
{"id": 981, "title": "GEL"}, {"id": 840, "title": "USD"},
{"id": 978, "title": "EUR"}, {"id": 643, "title": "RUB"}]}
RUB (643) სიაშია, მაგრამ კურსის მიღება მასზე შეუძლებელია (errorCode 2).
POST/api/v1/exchange/rateმომხმარებლის token
რამდენს მიიღებს მომხმარებელი amount-ის გადაცვლისას. ფული არ მოძრაობს.
| ველი | წესი |
|---|---|
from | საიდან: ვალუტის 3-ნიშნა კოდი (981, 840, 978) |
to | სად: ვალუტის 3-ნიშნა კოდი |
amount | თანხა from ვალუტაში, მაქსიმუმ 2 ათწილადით |
// მოთხოვნა
{"from": 981, "to": 840, "amount": 100}
// 200
{"errorCode": 0, "errorMessage": "Success",
"data": {"from": "GEL", "to": "USD", "amount": 100, "rate": 36.42}}
data.rate არის მისაღები თანხა to ვალუტაში და არა ერთეულის კურსი.
| errorCode (HTTP 402) | მნიშვნელობა |
|---|---|
| 9 | ვალიდაცია. ტექსტი message-შია. |
| 1 | პარამეტრი აკლია |
| 2 | ვალუტა არასწორია ან RUB-ია, დღევანდელი კურსი არ არის |
| 3 | მომხმარებელი ვერ მოიძებნა |
| 4 | მომხმარებელი არ არის ვერიფიცირებული |
| 5 | მომხმარებელი დაბლოკილია |
| 6 | AML შეზღუდვა |
| 7 | 2500-ზე მეტ თანხაზე სანქციების შემოწმება ვერ გაიარა |
POST/api/v1/exchange/convertმომხმარებლის token
გადაცვლის შესრულება: თანხა from ბალანსიდან ჩამოიჭრება და to ბალანსზე ჩაირიცხება. ველები და წარმატების პასუხი exchange/rate-ისას ემთხვევა. data.rate ჩარიცხული თანხაა.
// მოთხოვნა
{"from": 981, "to": 840, "amount": 100}
// 200: გადაცვლა შესრულდა
{"errorCode": 0, "errorMessage": "Success",
"data": {"from": "GEL", "to": "USD", "amount": 100, "rate": 36.42}}
SMS კოდი არ სჭირდება: მომხმარებელს გადაცვლა თქვენს აპლიკაციაში დაადასტურებინეთ, სანამ გამოიძახებთ.
911 / timeout-ზე არ გაიმეოროთ. შედეგი უცნობია: ჯერ user/transactions შეამოწმეთ. სანამ წინა გადაცვლა მუშავდება, იმავე მომხმარებლის ახალი გადაცვლა errorCode 11-ით ბრუნდება.
| პასუხი | მნიშვნელობა |
|---|---|
402, errorCode 1–7 | როგორც exchange/rate-ში |
402, errorCode 8 | თანხა 1-ზე ნაკლებია, ბალანსი არ კმარა, ან მომხმარებელს ვალიდური დოკუმენტი არ აქვს |
402, errorCode 9 | ვალიდაცია (ტექსტი message-შია) ან ჩაწერის შეცდომა |
402, errorCode 11 | ამ მომხმარებლის წინა გადაცვლა ჯერ მუშავდება. მოგვიანებით სცადეთ. |
402, {"message": "..."} | დოკუმენტის შემოწმება ვერ მოხერხდა, ან დოკუმენტი გაუქმებული/შეჩერებულია |
| 401 „ავტორიზაცია მუშავდება“ | დამატებითი შემოწმება (იხ. გამონაკლისი). სცადეთ მოგვიანებით. |
ვერიფიკაცია: როდის რა გამოიყენოთ
user-ის პასუხი სამ ველს შეიცავს, რომლებიც გეუბნებათ, რა უნდა გააკეთოს მომხმარებელმა:
| სიტუაცია | რა გამოიყენოთ |
|---|---|
პირადობის დოკუმენტს ვადა გაუვიდა (billing/pay აბრუნებს errorCode 8) ან ახალი დოკუმენტია საჭირო | verification/1 → verification/2: დოკუმენტის ხელახალი სკანირება და სელფი |
verification_defect: 1 | verification-defect/1 → 2 → 3: გამოტოვებული მონაცემების შევსება |
requested_document: 1 | requested-document: მოთხოვნილი სურათის ატვირთვა. რა სურათია საჭირო, წერია requested_document_comment-ში. |
POST/api/v1/verification/{step}მომხმარებლის token
step: 1 ან 2. პროცესი რეგისტრაციის დოკუმენტის ნაბიჯს ჰგავს (register/2–3).
- verification/1: ტანი ცარიელია. აბრუნებს
token-სა დაiframe_url-ს.{"token": "…64 სიმბოლო", "iframe_url": "https://widget.identomat.com/?session_token=…", "message": "Success"} iframe_urlმომხმარებელს გაუხსენით (კამერა საჭიროა). ვიჯეტის ენა ქართულია. თუ URL-შიsession_tokenცარიელია, სერვისი დროებით მიუწვდომელია: სცადეთ მოგვიანებით.- verification/2: ველი
token. ამოწმებს დოკუმენტს და ინახავს. რამდენიმე წუთი შეიძლება გაგრძელდეს: timeout მინიმუმ 310 წამი დააყენეთ.// 200 {"message": "Verification completed Success"} // 402: მაგალითები {"message": "user_checking"} // დოკუმენტი ხელით მოწმდება, სცადეთ მოგვიანებით {"message": "არასწორი დოკუმენტი!"} // დოკუმენტი სხვა პირისაა {"message": "SESSION_NOT_FOUND"} // token არასწორია ან სკანირება არ დასრულებულა
დოკუმენტის პირადი ნომერი მომხმარებლის პირად ნომერს უნდა ემთხვეოდეს.
POST/api/v1/verification-defect/{step}მომხმარებლის token
step: 1, 2 ან 3. გამოიყენეთ, როცა user-ში verification_defect: 1-ია: მომხმარებლის ანკეტაში მონაცემები აკლია.
verification-defect/1: ტანი ცარიელია. აბრუნებს, რომელი ველებია შესავსები.
// შესავსებია
{"errorCode": 1, "errorMessage": "შესავსებია გამოტოვებული ველები",
"data": {"employee_status": …, "real_address": …}}
// არაფერი აკლია
{"errorCode": 0, "errorMessage": "ვერიფიცირებული"}
data-ს გასაღებები ამ სიიდანაა: employee_status, monthly_income, expected_turnover, address_same, job_title, occupied_position, source_of_income_id, company_name, company_country, real_address, legal_address. ორივე პასუხი HTTP 200-ია.
verification-defect/2: გაგზავნეთ მხოლოდ ის ველები, რომლებიც ნაბიჯ 1-მა დააბრუნა. მნიშვნელობების სიები register/params-შია.
| ველი | წესი |
|---|---|
employee_status, monthly_income, expected_turnover | ID შესაბამისი სიიდან |
job_title, occupied_position | 3–100 სიმბოლო. ორივე სავალდებულოა, როცა employee_status = 1; როცა = 2, მხოლოდ occupied_position. |
source_of_income_id | სავალდებულოა, თუ employee_status = 3 |
company_name, company_country | სავალდებულოა, თუ employee_status არის 4 ან 5. company_name 2–100 სიმბოლო, company_country 2-ასოიანი კოდი. |
legal_address, real_address | 3–255 სიმბოლო |
address_same: 1, თუ ფაქტიური მისამართი იურიდიულს ემთხვევა; 0, თუ არ ემთხვევა. მაშინ real_address სავალდებულოა.
// 200: მომხმარებელს SMS მიუვა ანკეტის ბმულით და 6-ნიშნა კოდით
{"token": "…64 სიმბოლო", "message": "Success"}
// 402
{"message": "…ვალიდაციის ტექსტი…"}
{"message": "ატვირთული დოკუმენტი არავალიდურია!"} // ჯერ verification/1–2 გაიარეთ
ყოველი გამოძახება ახალ SMS-ს აგზავნის და წინა კოდს აუქმებს (იხ. შენიშვნა საერთო კოდზე). ლიმიტი: 10 წუთში 5 გამოძახება ერთ მომხმარებელზე.
verification-defect/3: ადასტურებს შევსებულ მონაცემებს.
| ველი | წესი |
|---|---|
token | ნაბიჯ 2-ის token |
sms | 6-ნიშნა კოდი SMS-დან |
// 200
{"message": "Success"}
// 402
{"message": "sms-ით მიღებული კოდი არასწორია"}
წარმატების შემდეგ user-ში verification_defect 0 ხდება.
POST/api/v1/requested-documentმომხმარებლის token
გამოიყენეთ, როცა user-ში requested_document: 1-ია. APW-მ მომხმარებელს სურათი მოსთხოვა: რა სურათი, წერია requested_document_comment-ში.
| ველი | წესი |
|---|---|
file | სურათი data URI-ად: data:image/png;base64,…. JPEG, PNG ან GIF, მაქსიმუმ 10 MB (base64-მდე). |
ეს ჩვეულებრივი JSON მოთხოვნაა და არა multipart. ხელმოწერის წესი იგივეა.
{"file": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ…"}
პასუხი ყოველთვის HTTP 200-ია. შედეგი errorCode-ით გაიგეთ:
| errorCode | მნიშვნელობა |
|---|---|
| 0 | სურათი აიტვირთა |
| 1 | ფაილი არასწორია: არ არის base64 სურათი, ფორმატი ან ზომა არ ემთხვევა |
| 2 | ამ მომხმარებლისგან სურათი არ არის მოთხოვნილი |
ბანკომატიდან გატანა (QR)
POST/api/v1/qr/verifyმომხმარებლის token
მომხმარებელი ბანკომატის ეკრანზე QR კოდს ასკანერებს და ნაღდ ფულს საფულიდან იღებს. ეს endpoint ბანკომატის სესიას მომხმარებლის საფულესთან აკავშირებს.
| ველი | წესი |
|---|---|
sessionId | სავალდებულო. ბანკომატის სესია, QR კოდიდან. |
atmId | სავალდებულო. ბანკომატის იდენტიფიკატორი, QR კოდიდან. |
// 200
{"errorCode": 0, "errorMessage": "Success"}
SMS კოდი არ სჭირდება: გამოძახებამდე მომხმარებელს თქვენს აპლიკაციაში დაადასტურებინეთ, რომ ბანკომატთან თვითონ დგას. ეს მოთხოვნა რამდენიმე წუთს შეიძლება გაგრძელდეს.
| პასუხი (HTTP 402) | მნიშვნელობა |
|---|---|
errorCode 9 | მომხმარებელი დაბლოკილია, არ არის ვერიფიცირებული, ან AML შეზღუდვა აქვს |
errorCode 8 | ვალიდური დოკუმენტი არ აქვს, ან QR-ის მონაცემები არასწორია |
სხვა errorCode | ბანკომატის სერვისის პასუხი. ტექსტი errorMessage-შია. |
{"message": "..."} | ველის ვალიდაცია ან დოკუმენტის შემოწმების შეცდომა |