Download OpenAPI specification:
OpenAPI specification for the Bargardon translation service.
Stack: Laravel 13, PHP ≥ 8.3, Laravel Sanctum 4.
Authentication: Obtain a token with POST /login, then send Authorization: Bearer {token} on subsequent requests.
POST /translations runs behind billing middleware (rate limits, wallet balance, active API key, etc.). You may send an optional Idempotency-Key header for safe retries; duplicate keys may return a cached response with an Idempotency-Replayed header.
Full Markdown documentation: Docs/API_DOCUMENTATION.md
Interactive docs are served at /api-docs (this file).
Authenticate with email and password. Returns a Sanctum personal access token for Authorization: Bearer ....
Example request:
{ "email": "user@example.com", "password": "your-password" }
| email required | string <email> Account email address |
| password required | string <password> Account password |
{- "email": "user@example.com",
- "password": "password123"
}{- "success": true,
- "data": {
- "user": {
- "id": 1,
- "name": "John Doe",
- "email": "user@example.com"
}, - "token": "1|abcdefghijklmnopqrstuvwxyz1234567890",
- "token_type": "Bearer"
}
}Returns the authenticated user model as JSON (Sanctum-protected).
{- "id": 1,
- "name": "John Doe",
- "email": "user@example.com",
- "email_verified_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Creates a new personal access token. The plaintext token is returned once in data.token; store it securely.
Example:
{ "name": "CI / Production" }
| name required | string <= 255 characters Human-readable label for the token |
{- "name": "My New API Token"
}{- "success": true,
- "data": {
- "token": "2|abcdefghijklmnopqrstuvwxyz1234567890",
- "token_name": "My New API Token",
- "token_type": "Bearer"
}
}Deletes a token by ID. The ID is the numeric identifier from the list endpoint (may be passed as string or integer in the path).
| tokenId required | string Example: 1 Personal access token ID |
{- "success": true,
- "message": "Token revoked successfully"
}Submit text for translation. Content is split into sentences and processed via Google Sheets (GOOGLETRANSLATE).
Billing: Subject to RPM limits, wallet balance, and related billing rules; may return 429 when throttled or 402 when payment is required.
Wait: Default poll/wait window is 5 seconds; override with wait_seconds (1–60).
Optional header Idempotency-Key: Send a unique key per logical request to avoid duplicate charges; replays may include Idempotency-Replayed: true.
Example body:
{
"text": "Hello world. This is a test.",
"source_language": "en",
"target_language": "fa",
"wait_seconds": 5
}
| Idempotency-Key | string Unique key for idempotent translation requests |
| text required | string Source text to translate |
| source_language required | string = 2 characters Source language code (e.g. |
| target_language required | string = 2 characters Target language code |
| wait_seconds | integer [ 1 .. 60 ] Default: 5 Seconds to wait for translation completion |
{- "text": "Hello world. This is a test.",
- "source_language": "en",
- "target_language": "fa",
- "wait_seconds": 5
}{- "success": true,
- "data": {
- "id": 1,
- "original_text": "Hello world. This is a test.",
- "translated_text": "سلام دنیا. این یک تست است.",
- "source_language": "en",
- "target_language": "fa",
- "status": "completed",
- "created_at": "2019-08-24T14:15:22Z"
}
}Returns the current user's wallet (created on first access if missing).
Balances are in Iranian rials (*_rials fields).
Example response (data):
{
"id": 1,
"balance_rials": 75000,
"frozen_rials": 0,
"lifetime_spent_rials": 120000,
"low_balance_threshold_rials": 25000,
"auto_topup": {
"enabled": false,
"threshold_rials": 0,
"amount_rials": 0
},
"updated_at": "2026-05-01T12:00:00.000000Z"
}
{- "data": {
- "id": 1,
- "balance_rials": 75000,
- "frozen_rials": 0,
- "lifetime_spent_rials": 120000,
- "low_balance_threshold_rials": 25000,
- "auto_topup": {
- "enabled": true,
- "threshold_rials": 0,
- "amount_rials": 0
}, - "updated_at": "2019-08-24T14:15:22Z"
}
}Partial update of low-balance alert threshold and optional auto top-up settings.
Example:
{
"low_balance_threshold_rials": 25000,
"auto_topup_enabled": true,
"auto_topup_threshold_rials": 20000,
"auto_topup_amount_rials": 500000
}
| low_balance_threshold_rials | integer >= 0 Notify or trigger threshold (rials) |
| auto_topup_enabled | boolean |
| auto_topup_threshold_rials | integer >= 0 |
| auto_topup_amount_rials | integer >= 0 |
{- "low_balance_threshold_rials": 0,
- "auto_topup_enabled": true,
- "auto_topup_threshold_rials": 0,
- "auto_topup_amount_rials": 0
}{- "data": {
- "id": 1,
- "balance_rials": 75000,
- "frozen_rials": 0,
- "lifetime_spent_rials": 120000,
- "low_balance_threshold_rials": 25000,
- "auto_topup": {
- "enabled": true,
- "threshold_rials": 0,
- "amount_rials": 0
}, - "updated_at": "2019-08-24T14:15:22Z"
}
}Paginated ledger entries (credits, debits, reserves, top-ups, etc.).
Query parameters:
type — filter by WalletTransactionType (e.g. topup, debit, credit)from / to — filter created_at (inclusive bounds as interpreted by the backend)per_page — page size (1–100, default 25)Example: GET /wallet/transactions?type=topup&per_page=10
| type | string Enum: "credit" "debit" "reserve" "release" "settle_adjust" "refund" "promo_grant" "topup" "adjustment" |
| from | string <date-time> Lower bound for created_at |
| to | string <date-time> Upper bound for created_at |
| per_page | integer [ 1 .. 100 ] Default: 25 |
{- "data": [
- {
- "id": 0,
- "type": "credit",
- "status": "pending",
- "amount_rials": 0,
- "balance_after_rials": 0,
- "description": "string",
- "reference_type": "string",
- "reference_id": "string",
- "metadata": { },
- "created_at": "2019-08-24T14:15:22Z"
}
], - "links": {
- "first": "string",
- "last": "string",
- "prev": "string",
- "next": "string"
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "path": "string",
- "per_page": 0,
- "to": 0,
- "total": 0
}
}Paginated API usage records (endpoint, units, costs, status).
Query: endpoint, status (reserved, settled, failed, refunded), per_page (1–100, default 25).
Example: GET /wallet/usage?status=settled&per_page=20
| endpoint | string |
| status | string Enum: "reserved" "settled" "failed" "refunded" |
| per_page | integer [ 1 .. 100 ] Default: 25 |
{- "data": [
- {
- "id": "string",
- "endpoint": "api/translations",
- "method": "POST",
- "units_consumed": 0,
- "estimated_cost_rials": 0,
- "final_cost_rials": 0,
- "status": "reserved",
- "duration_ms": 0,
- "response_code": 0,
- "created_at": "2019-08-24T14:15:22Z"
}
], - "links": {
- "first": "string",
- "last": "string",
- "prev": "string",
- "next": "string"
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "path": "string",
- "per_page": 0,
- "to": 0,
- "total": 0
}
}Aggregates usage over a sliding window: day (default), week, or month.
Returns per-day rows plus totals for the selected period.
Example: GET /wallet/usage/stats?period=week
| period | string Default: "day" Enum: "day" "week" "month" |
{- "success": true,
- "period": "day",
- "data": [
- {
- "day": "2026-05-01",
- "requests": 42,
- "cost_rials": 150000,
- "units": 18000
}
], - "totals": {
- "requests": 0,
- "cost_rials": 0,
- "units": 0
}
}Creates a pending payment and returns a gateway redirect URL for the user to complete payment.
amount_rials is required (10_000–1_000_000_000 rials).callback_url is optional (stored on the transaction; gateway callback also uses the app route payments.callback).gateway is optional; defaults to config('payments.default') (e.g. Zarinpal).Example:
{
"amount_rials": 500000,
"gateway": "zarinpal",
"callback_url": "https://your-app.example/profile/wallet"
}
| amount_rials required | integer [ 10000 .. 1000000000 ] Top-up amount in rials |
| callback_url | string or null <uri> Optional client callback URL stored on the payment record |
| gateway | string Payment driver name (must be configured in the app) |
{- "amount_rials": 500000,
- "gateway": "zarinpal"
}{- "success": true,
- "data": {
- "payment": {
- "id": 0,
- "amount_rials": 0,
- "gateway": "zarinpal",
- "status": "pending",
- "gateway_authority": "string",
- "gateway_ref": "string",
- "paid_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z"
},
}
}Returns languages ordered by name. Optional filters:
is_active — booleancode — exact language codehas_active_courses — when true, only languages tied to published courses (source or target)Note: The JSON key for the collection is language (singular), not languages.
Example: GET /languages?is_active=true
| is_active | boolean |
| code | string Example: code=en |
| has_active_courses | boolean |
{- "status": "success",
- "language": [
- {
- "id": 0,
- "name": "English",
- "code": "en",
- "native_name": "English",
- "description": "string",
- "flag_icon": "string",
- "is_active": true,
- "is_rtl": true,
- "countries": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "deleted_at": "2019-08-24T14:15:22Z"
}
]
}Creates a language record. Validation errors use status: error and an errors object (not identical to Laravel's default JSON shape).
Example:
{
"name": "English",
"code": "en",
"native_name": "English",
"description": "English language",
"is_active": true,
"is_rtl": false,
"countries": ["US", "GB"]
}
| name required | string <= 255 characters Must be unique |
| code required | string <= 5 characters Must be unique (ISO-style code) |
| native_name required | string <= 255 characters |
| description | string or null |
| flag_icon | string or null <= 255 characters |
| is_active | boolean |
| is_rtl | boolean |
| countries | Array of strings or null |
{- "name": "string",
- "code": "strin",
- "native_name": "string",
- "description": "string",
- "flag_icon": "string",
- "is_active": true,
- "is_rtl": true,
- "countries": [
- "string"
]
}{- "status": "success",
- "message": "Language created successfully",
- "language": {
- "id": 0,
- "name": "English",
- "code": "en",
- "native_name": "English",
- "description": "string",
- "flag_icon": "string",
- "is_active": true,
- "is_rtl": true,
- "countries": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "deleted_at": "2019-08-24T14:15:22Z"
}
}Returns a single language by ID.
| language required | integer Example: 1 Language ID (route-model binding) |
{- "status": "success",
- "language": {
- "id": 0,
- "name": "English",
- "code": "en",
- "native_name": "English",
- "description": "string",
- "flag_icon": "string",
- "is_active": true,
- "is_rtl": true,
- "countries": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "deleted_at": "2019-08-24T14:15:22Z"
}
}Full or partial update via PUT. All fields optional except uniqueness rules apply when a field is present.
Example:
{ "is_active": false, "description": "Archived" }
| language required | integer Example: 1 Language ID (route-model binding) |
| name | string <= 255 characters |
| code | string <= 10 characters |
| native_name | string <= 255 characters |
| description | string or null |
| flag_icon | string or null <= 255 characters |
| is_active | boolean |
| is_rtl | boolean |
| countries | Array of strings or null |
{- "name": "string",
- "code": "string",
- "native_name": "string",
- "description": "string",
- "flag_icon": "string",
- "is_active": true,
- "is_rtl": true,
- "countries": [
- "string"
]
}{- "status": "success",
- "message": "Language updated successfully",
- "language": {
- "id": 0,
- "name": "English",
- "code": "en",
- "native_name": "English",
- "description": "string",
- "flag_icon": "string",
- "is_active": true,
- "is_rtl": true,
- "countries": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "deleted_at": "2019-08-24T14:15:22Z"
}
}Soft-deletes the language (if the model uses soft deletes).
| language required | integer Example: 1 Language ID (route-model binding) |
{- "status": "success",
- "message": "Language deleted successfully"
}