Skip to main content

PaytechUZ API Documentation

Base URL: https://paytechuz-core.uz/api


Health Check

Ping

curl -X GET https://paytechuz-core.uz/api/ping/

Response (200):

{
"status": "ok"
}

Authentication

Send OTP

Send OTP to phone number. User retrieves code via Telegram bot.

curl -X POST https://paytechuz-core.uz/api/auth/send-otp/ \
-H "Content-Type: application/json" \
-d '{"phone": "+998901234567"}'

Request Body:

FieldTypeRequiredDescription
phonestringYesPhone number (+998XXXXXXXXX format)

Response (200):

{
"message": "OTP created. Get your code via Telegram bot.",
"expires_in": 120
}

Error Response (400):

{
"phone": ["Invalid phone number format"]
}

Verify OTP

Verify OTP code and receive JWT tokens.

curl -X POST https://paytechuz-core.uz/api/auth/verify-otp/ \
-H "Content-Type: application/json" \
-d '{"phone": "+998901234567", "code": "123456"}'

Request Body:

FieldTypeRequiredDescription
phonestringYesPhone number
codestringYes6-digit OTP code

Response (200):

{
"is_new_user": true,
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}

Error Responses (400):

{"detail": "OTP not found"}
{"detail": "OTP has expired"}
{"detail": "Too many attempts"}
{"detail": "Invalid code. 2 attempts remaining"}

Get Profile

Get user profile details (requires authentication).

curl -X GET https://paytechuz-core.uz/api/auth/profile/ \
-H "Authorization: Bearer <access_token>"

Response (200):

{
"id": 1,
"phone": "+998901234567",
"first_name": "John",
"last_name": "Doe",
"created_at": "2024-01-15T10:30:00Z"
}

Update Profile

Update user profile (requires authentication).

curl -X PUT https://paytechuz-core.uz/api/auth/profile/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-d '{"first_name": "John", "last_name": "Doe"}'

Request Body:

FieldTypeRequiredDescription
first_namestringYesFirst name (max 150 chars)
last_namestringNoLast name (max 150 chars)

Response (200):

{
"message": "Profile updated successfully"
}

Projects

All project endpoints require authentication.

List Projects

curl -X GET https://paytechuz-core.uz/api/projects/ \
-H "Authorization: Bearer <access_token>"

Response (200):

[
{
"id": 1,
"name": "My Project",
"created_at": "2024-01-15T10:30:00Z",
"subscription": {
"tariff": "Basic",
"requests_limit": 1000,
"requests_used": 150,
"requests_remaining": 850,
"is_active": true,
"is_expired": false,
"expires_at": "2024-02-15T10:30:00Z"
}
},
{
"id": 2,
"name": "Another Project",
"created_at": "2024-01-16T14:20:00Z",
"subscription": null
}
]

Create Project

Creates a new project with default API key and free trial subscription.

curl -X POST https://paytechuz-core.uz/api/projects/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-d '{"name": "My New Project"}'

Request Body:

FieldTypeRequiredDescription
namestringYesProject name (max 255 chars)

Response (201):

{
"id": 1,
"name": "My New Project",
"api_key": "550e8400-e29b-41d4-a716-446655440000",
"tariff": "Free Trial",
"requests_limit": 100,
"expires_at": "2024-02-15T10:30:00Z",
"created_at": "2024-01-15T10:30:00Z"
}

Error Response (400):

{
"detail": "Project limit reached. Maximum 3 projects allowed."
}

Delete Project

curl -X DELETE https://paytechuz-core.uz/api/projects/1/ \
-H "Authorization: Bearer <access_token>"

Response (200):

{
"message": "Project deleted successfully"
}

Error Response (400):

{
"detail": "Project not found"
}

List API Keys

List all active API keys for a project.

curl -X GET https://paytechuz-core.uz/api/projects/1/api-keys/ \
-H "Authorization: Bearer <access_token>"

Response (200):

[
{
"id": 1,
"key": "550e8400-e29b-41d4-a716-446655440000",
"name": "default",
"created_at": "2024-01-15T10:30:00Z"
},
{
"id": 2,
"key": "660e8400-e29b-41d4-a716-446655440001",
"name": "production",
"created_at": "2024-01-16T14:20:00Z"
}
]

Create API Key

Generate a new API key for a project.

curl -X POST https://paytechuz-core.uz/api/projects/1/api-keys/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-d '{"name": "production"}'

Request Body:

FieldTypeRequiredDescription
namestringNoKey name (max 255 chars)

Response (201):

{
"id": 2,
"key": "660e8400-e29b-41d4-a716-446655440001",
"name": "production",
"project_id": 1,
"created_at": "2024-01-16T14:20:00Z"
}

Revoke API Key

curl -X DELETE https://paytechuz-core.uz/api/api-keys/2/ \
-H "Authorization: Bearer <access_token>"

Response (200):

{
"message": "API key revoked successfully"
}

Error Response (400):

{
"detail": "API key not found"
}

Tariffs

List Tariffs

List all available tariffs (public endpoint).

curl -X GET https://paytechuz-core.uz/api/tariffs/

Response (200):

[
{
"id": 1,
"name": "Free Trial",
"slug": "free-trial",
"requests_limit": 100,
"price": "0.00",
"duration_days": 30
},
{
"id": 2,
"name": "Basic",
"slug": "basic",
"requests_limit": 1000,
"price": "9.99",
"duration_days": 30
},
{
"id": 3,
"name": "Pro",
"slug": "pro",
"requests_limit": 10000,
"price": "49.99",
"duration_days": 30
}
]

Subscribe to Tariff

Subscribe a project to a tariff (requires authentication).

  • Free trial: Activates immediately
  • Paid tariffs: Returns payment URL (Payme)
curl -X POST https://paytechuz-core.uz/api/tariffs/subscribe/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-d '{"project_id": 1, "tariff_slug": "basic", "return_url": "https://myapp.com/success"}'

Request Body:

FieldTypeRequiredDescription
project_idintegerYesProject ID
tariff_slugstringYesTariff slug
return_urlstringNoURL to redirect after payment

Response (201) - Free Trial (immediate activation):

{
"id": 1,
"tariff": "Free Trial",
"requests_limit": 100,
"requests_used": 0,
"requests_remaining": 100,
"expires_at": "2024-02-15T10:30:00Z"
}

Response (201) - Paid Tariff (requires payment):

{
"requires_payment": true,
"invoice_id": 1,
"payment_url": "https://checkout.paycom.uz/base64encodedstring",
"amount": "9.99",
"tariff": "Basic"
}

Error Responses (400):

{"detail": "Project not found"}
{"detail": "Tariff not found"}

Get Subscription Status

Get current subscription status for a project (requires authentication).

curl -X GET https://paytechuz-core.uz/api/tariffs/projects/1/status/ \
-H "Authorization: Bearer <access_token>"

Response (200) - Active subscription:

{
"has_subscription": true,
"tariff": "Basic",
"requests_limit": 1000,
"requests_used": 150,
"requests_remaining": 850,
"is_expired": false,
"expires_at": "2024-02-15T10:30:00Z"
}

Response (200) - No subscription:

{
"has_subscription": false,
"message": "No active subscription"
}

Check API Key

Check API key status and remaining requests (public endpoint).

curl -X POST https://paytechuz-core.uz/api/tariffs/check-api-key/ \
-H "Content-Type: application/json" \
-d '{"api_key": "550e8400-e29b-41d4-a716-446655440000"}'

Request Body:

FieldTypeRequiredDescription
api_keyuuidYesAPI key UUID

Response (200) - Valid:

{
"valid": true,
"project_id": 1,
"project_name": "My Project",
"tariff": "Basic",
"requests_remaining": 850,
"expires_at": "2024-02-15T10:30:00Z"
}

Response (200) - Invalid:

{
"valid": false,
"error": "No active subscription for this project"
}
{
"valid": false,
"error": "Subscription has expired"
}
{
"valid": false,
"error": "Request limit exceeded"
}

Error Response (400):

{
"detail": "Invalid or inactive API key"
}

Use Request

Consume one request from API key's quota (public endpoint).

curl -X POST https://paytechuz-core.uz/api/tariffs/use-request/ \
-H "Content-Type: application/json" \
-d '{"api_key": "550e8400-e29b-41d4-a716-446655440000"}'

Request Body:

FieldTypeRequiredDescription
api_keyuuidYesAPI key UUID

Response (200) - Success:

{
"success": true,
"requests_used": 151,
"requests_remaining": 849,
"requests_limit": 1000
}

Response (200) - Failure:

{
"success": false,
"error": "Invalid or inactive API key"
}
{
"success": false,
"error": "No active subscription"
}
{
"success": false,
"error": "Subscription expired"
}
{
"success": false,
"error": "Request limit exceeded"
}

Error Responses

Authentication Errors

401 Unauthorized:

{
"detail": "Authentication credentials were not provided."
}
{
"detail": "Given token not valid for any token type",
"code": "token_not_valid",
"messages": [
{
"token_class": "AccessToken",
"token_type": "access",
"message": "Token is invalid or expired"
}
]
}

Validation Errors

400 Bad Request:

{
"field_name": ["Error message"]
}

Rate Limiting

429 Too Many Requests:

{
"detail": "Request was throttled. Expected available in X seconds."
}

Payment

Get Payment Status

Check the status of a payment/invoice (requires authentication).

curl -X GET https://paytechuz-core.uz/api/payment/status/1/ \
-H "Authorization: Bearer <access_token>"

Response (200) - Found:

{
"found": true,
"invoice_id": 1,
"project_id": 7,
"project_name": "My Project",
"tariff": "Basic",
"amount": "9.99",
"status": "pending",
"provider": "payme",
"payment_url": "https://checkout.paycom.uz/base64encodedstring",
"created_at": "2024-01-15T10:30:00Z"
}

Invoice Status Values:

StatusDescription
pendingPayment not yet completed
paidPayment successful, subscription activated
cancelledPayment was cancelled
expiredPayment expired

Response (200) - Not Found:

{
"found": false,
"error": "Invoice not found"
}

Payment Flow

  1. User calls POST /api/tariffs/subscribe/ with return_url
  2. For paid tariffs, API returns payment_url and invoice_id
  3. User is redirected to Payme checkout
  4. After payment, user is redirected to return_url?invoice_id=123
  5. Frontend extracts invoice_id from URL query params
  6. Frontend calls GET /api/payment/status/{invoice_id}/ to verify payment
  7. If status is paid, subscription is active