Documentation Index
Fetch the complete documentation index at: https://docs.foodsave.kz/llms.txt
Use this file to discover all available pages before exploring further.
Authentication API
Base path: /api/v1/auth
Overview
FoodSave uses OTP-based login for end users and short-lived JWT access tokens for authenticated requests.
OTP sends are rate-limited to 3 requests per 5 minutes per phone number.
POST /api/v1/auth/otp/send
Send an OTP code to a phone number.
curl --request POST \
--url https://api.foodsave.kz/api/v1/auth/otp/send \
-H 'Content-Type: application/json' \
-d '{"phone":"+77001234567"}'
const response = await fetch('https://api.foodsave.kz/api/v1/auth/otp/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone: '+77001234567' })
})
console.log(await response.json())
import requests
response = requests.post(
'https://api.foodsave.kz/api/v1/auth/otp/send',
json={'phone': '+77001234567'}
)
print(response.json())
{ "message": "OTP sent", "retryAfterSeconds": 300 }
Errors
| Code | Meaning | How to fix |
|---|
| 400 | BAD_REQUEST | Check phone format +7XXXXXXXXXX |
| 429 | RATE_LIMIT | Wait for retryAfterSeconds |
POST /api/v1/auth/otp/verify
Verify the OTP and receive tokens.
curl --request POST \
--url https://api.foodsave.kz/api/v1/auth/otp/verify \
-H 'Content-Type: application/json' \
-d '{"phone":"+77001234567","code":"123456"}'
const response = await fetch('https://api.foodsave.kz/api/v1/auth/otp/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone: '+77001234567', code: '123456' })
})
console.log(await response.json())
import requests
response = requests.post(
'https://api.foodsave.kz/api/v1/auth/otp/verify',
json={'phone': '+77001234567', 'code': '123456'}
)
print(response.json())
{
"accessToken": "eyJhbGciOi...",
"refreshToken": "def50200...",
"tokenType": "Bearer",
"expiresIn": 3600
}
Errors
| Code | Meaning | How to fix |
|---|
| 400 | INVALID_CODE | Request a new OTP and try again |
| 401 | EXPIRED_CODE | Send OTP again |
POST /api/v1/auth/token/refresh
Refresh an access token.
curl --request POST \
--url https://api.foodsave.kz/api/v1/auth/token/refresh \
-H 'Content-Type: application/json' \
-d '{"refreshToken":"def50200..."}'
const response = await fetch('https://api.foodsave.kz/api/v1/auth/token/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken: 'def50200...' })
})
console.log(await response.json())
import requests
response = requests.post(
'https://api.foodsave.kz/api/v1/auth/token/refresh',
json={'refreshToken': 'def50200...'}
)
print(response.json())
{ "accessToken": "eyJhbGciOi...", "refreshToken": "def50200...", "tokenType": "Bearer", "expiresIn": 3600 }
Errors
| Code | Meaning | How to fix |
|---|
| 401 | INVALID_REFRESH_TOKEN | Re-authenticate via OTP |
POST /api/v1/auth/logout
Invalidate a refresh token.
curl --request POST \
--url https://api.foodsave.kz/api/v1/auth/logout \
-H 'Content-Type: application/json' \
-d '{"refreshToken":"def50200..."}'
const response = await fetch('https://api.foodsave.kz/api/v1/auth/logout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken: 'def50200...' })
})
console.log(response.status)
import requests
response = requests.post(
'https://api.foodsave.kz/api/v1/auth/logout',
json={'refreshToken': 'def50200...'}
)
print(response.status_code)
Errors
| Code | Meaning | How to fix |
|---|
| 400 | INVALID_TOKEN | Supply a valid refresh token |