diff --git a/api-reference/classify.mdx b/api-reference/classify.mdx
index ac3d730..40a5a57 100644
--- a/api-reference/classify.mdx
+++ b/api-reference/classify.mdx
@@ -1,18 +1,20 @@
---
-title: "Classify Comment"
+title: "Classify text"
sidebarTitle: "POST /v1/classify"
-description: "Classify an Arabic or English comment by intent, sentiment, dialect, and toxicity in a single API call."
+description: "Classify Arabic or English text by intent, sentiment, dialect, and priority in a single API call."
api: "POST https://api.trynawa.com/v1/classify"
---
-Classify any comment with a single request. Returns intent, sentiment, dialect, and toxicity analysis. Arabic comments are routed to HUMAIN's ALLaM model for dialect detection. English comments are routed to Claude for high-accuracy classification.
+Classify any comment with a single request. Returns intent, sentiment, dialect, priority, and whether a response is needed.
-## Request
+Arabic comments (including Arabizi) are routed to ALLaM. English comments are routed to Claude. Common Arabizi patterns like greetings and praise are classified instantly via a local rubric without an LLM call.
- Cost: **$0.006** per request. Semantic cache hits are free (`X-NAWA-Cache: HIT`).
+ Cost: **$0.006** per request (6 credits). Semantic cache hits are free (`X-NAWA-Cache: HIT`).
+## Request
+
### Headers
| Header | Required | Description |
@@ -20,11 +22,17 @@ Classify any comment with a single request. Returns intent, sentiment, dialect,
| `Authorization` | Yes | `Bearer nawa_live_sk_xxx` or `Bearer nawa_test_sk_xxx` |
| `Content-Type` | Yes | `application/json` |
+### Query parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `provider` | string | No | Force a specific AI provider: `claude`, `gemini`, `allam`. Bypasses automatic language-based routing. Useful for A/B testing. |
+
### Body parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
-| `text` | string | Yes | The comment text to classify. Max 5,000 characters. |
+| `text` | string | Yes | The comment text to classify. Supports Arabic script, Arabizi (Latin-script Arabic like `7abibi`), and English. Max 5,000 characters. |
| `platform` | string | No | Source platform: `youtube`, `instagram`, `twitter`, `facebook`. Improves accuracy with platform-specific context. |
| `channel_id` | string | No | Your channel or account identifier for analytics grouping. |
| `metadata` | object | No | Arbitrary key-value metadata to attach to the classification. |
@@ -35,7 +43,7 @@ Classify any comment with a single request. Returns intent, sentiment, dialect,
```bash cURL
curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"text": "متى الجزء الثاني؟",
@@ -44,6 +52,18 @@ curl -X POST https://api.trynawa.com/v1/classify \
}'
```
+```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="nawa_live_sk_xxx")
+
+result = nawa.classify(
+ text="متى الجزء الثاني؟",
+ platform="youtube",
+ channel_id="ch_123"
+)
+```
+
```typescript TypeScript
import { Nawa } from '@nawalabs/sdk'
@@ -56,18 +76,6 @@ const { data, error } = await nawa.classify({
})
```
-```python Python
-from nawa import Nawa
-
-nawa = Nawa(api_key="your_api_key")
-
-result = nawa.classify(
- text="متى الجزء الثاني؟",
- platform="youtube",
- channel_id="ch_123"
-)
-```
-
## Response
@@ -78,22 +86,28 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "متى الجزء الثاني؟",
- "intent": "question",
- "intent_confidence": 0.97,
+ "id": "cls_nw_a1b2c3d4e5f6",
+ "object": "classification",
+ "intent": ["question"],
"sentiment": "neutral",
- "sentiment_confidence": 0.91,
+ "language": "ar",
"dialect": "gulf",
"dialect_confidence": 0.95,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "ar",
- "model": "nagl-v1",
- "cached": false
+ "requires_response": true,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "",
+ "direction": "rtl"
+ },
+ "provider": "allam",
+ "model": "allam-13b",
+ "fallback_used": false,
+ "tokens_used": null,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_abc123def456"
+ "request_id": "req_nw_a1b2c3d4e5f67890"
}
```
@@ -102,50 +116,80 @@ result = nawa.classify(
| Header | Description |
|--------|-------------|
| `X-Request-Id` | Unique request identifier for debugging |
+| `X-NAWA-Provider` | AI provider used (`allam`, `claude`, or `gemini`) |
+| `X-NAWA-Cache` | `HIT` if served from semantic cache (no cost), `MISS` otherwise |
+| `X-NAWA-Balance` | Current credit balance in USD |
| `X-RateLimit-Limit` | Rate limit ceiling for current window |
| `X-RateLimit-Remaining` | Requests remaining in current window |
| `X-RateLimit-Reset` | Window reset time (RFC 3339) |
-| `X-NAWA-Balance` | Current credit balance in USD |
-| `X-NAWA-Balance-Warning` | `low_balance` when below $5 |
-| `X-NAWA-Cache` | `HIT` if served from semantic cache (no cost) |
### Result fields
| Field | Type | Description |
|-------|------|-------------|
-| `text` | string | The original input text |
-| `intent` | string | `question`, `complaint`, `praise`, `suggestion`, `spam`, `other` |
-| `intent_confidence` | number | Confidence score (0–1) |
-| `sentiment` | string | `positive`, `negative`, `neutral`, `mixed` |
-| `sentiment_confidence` | number | Confidence score (0–1) |
-| `dialect` | string \| null | `gulf`, `egyptian`, `levantine`, `msa`. Returns `null` for English text. |
-| `dialect_confidence` | number \| null | Confidence score (0-1). Returns `null` for English text. |
-| `toxicity` | string | `none`, `mild`, `moderate`, `severe` |
-| `toxicity_confidence` | number | Confidence score (0–1) |
-| `categories` | string[] | Content categories: `engagement`, `support`, `feedback`, `spam` |
-| `language` | string | Detected language code (e.g., `ar`, `en`) |
-| `model` | string | Model version used for classification |
-| `cached` | boolean | Whether this was served from semantic cache |
+| `id` | string | Classification ID in `cls_nw_xxx` format |
+| `object` | string | Always `"classification"` |
+| `intent` | string[] | Detected intents (e.g. `["praise"]`, `["question", "complaint"]`) |
+| `sentiment` | string | `positive`, `negative`, `neutral`, or `mixed` |
+| `language` | string | Detected language: `ar`, `en`, or `mixed` |
+| `dialect` | string \| null | Arabic dialect: `gulf`, `egyptian`, `levantine`, `maghrebi`, `msa`. Null for English. |
+| `dialect_confidence` | number \| null | Dialect confidence (0-1). Null for English. |
+| `requires_response` | boolean | Whether this comment needs a reply |
+| `priority` | string | `high`, `medium`, or `low` |
+| `suggested_reply` | object | Reply direction hint |
+| `suggested_reply.text` | string | Summary text (may be empty) |
+| `suggested_reply.direction` | string | `rtl` for Arabic, `ltr` for English |
+| `provider` | string | AI provider used: `allam`, `claude`, or `gemini` |
+| `model` | string | Model identifier (e.g. `allam-13b`, `claude-sonnet-4-5-20250929`, `arabizi-rubric`) |
+| `fallback_used` | boolean | Whether the primary provider failed and a fallback was used |
+| `tokens_used` | integer \| null | Token count (currently always null) |
+| `cost_usd` | number | Cost in USD |
+| `credits_used` | integer | Credits consumed |
### Error responses
| Status | Type | When |
|--------|------|------|
-| 400 | `invalid_request_error` | Missing `text`, invalid `platform`, text too long |
+| 400 | `invalid_request_error` | Missing `text`, invalid `provider` query param, text empty |
| 401 | `authentication_error` | Invalid or missing API key |
-| 402 | `insufficient_credits` | No credits remaining |
+| 402 | `permission_error` | No credits remaining |
| 429 | `rate_limit_error` | Rate limit exceeded |
| 500 | `api_error` | Internal or provider error |
+## Provider routing
+
+NAWA automatically selects the best AI provider based on the detected language:
+
+| Language | Primary | Fallback 1 | Fallback 2 |
+|----------|---------|------------|------------|
+| Arabic (`ar`) | ALLaM | Claude | Gemini |
+| Mixed | ALLaM | Claude | Gemini |
+| English (`en`) | Claude | Gemini | ALLaM |
+
+Use the `?provider=` query parameter to override this routing for A/B testing:
+
+```bash
+curl -X POST "https://api.trynawa.com/v1/classify?provider=claude" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
+ -H "Content-Type: application/json" \
+ -d '{"text": "ما شاء الله عليك"}'
+```
+
+## Arabizi support
+
+NAWA detects Arabizi (Latin-script Arabic that uses numbers for Arabic sounds, like `7` for ح and `3` for ع) automatically. Arabizi text is transliterated to Arabic script before classification, so the language is detected as `ar`.
+
+Common Arabizi greetings and praise are classified instantly via a local pattern matcher (model: `arabizi-rubric`) without an LLM call.
+
### More examples
-
+
```bash
curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
- -d '{"text": "This is hands down the best review I have seen on this phone. Subscribed!", "platform": "youtube"}'
+ -d '{"text": "9ba7oooo ya 7abibi el video 7elo kter", "platform": "youtube"}'
```
Response:
@@ -153,32 +197,38 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "This is hands down the best review I have seen on this phone. Subscribed!",
- "intent": "praise",
- "intent_confidence": 0.96,
+ "id": "cls_nw_f7e8d9c0b1a2",
+ "object": "classification",
+ "intent": ["praise"],
"sentiment": "positive",
- "sentiment_confidence": 0.98,
+ "language": "ar",
"dialect": null,
"dialect_confidence": null,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "en",
- "model": "claude-v1",
- "cached": false
+ "requires_response": false,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "",
+ "direction": "rtl"
+ },
+ "provider": "claude",
+ "model": "arabizi-rubric",
+ "fallback_used": false,
+ "tokens_used": null,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_en_praise_001"
+ "request_id": "req_nw_b2c3d4e5f67890ab"
}
```
-
+
```bash
curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
- -d '{"text": "The audio quality is terrible in this one. Can barely hear anything after the 5 minute mark.", "platform": "youtube"}'
+ -d '{"text": "This is hands down the best review I have seen on this phone. Subscribed!", "platform": "youtube"}'
```
Response:
@@ -186,32 +236,38 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "The audio quality is terrible in this one. Can barely hear anything after the 5 minute mark.",
- "intent": "complaint",
- "intent_confidence": 0.94,
- "sentiment": "negative",
- "sentiment_confidence": 0.96,
+ "id": "cls_nw_c3d4e5f6a7b8",
+ "object": "classification",
+ "intent": ["praise"],
+ "sentiment": "positive",
+ "language": "en",
"dialect": null,
"dialect_confidence": null,
- "toxicity": "none",
- "toxicity_confidence": 0.97,
- "categories": ["feedback"],
- "language": "en",
- "model": "claude-v1",
- "cached": false
+ "requires_response": false,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "",
+ "direction": "ltr"
+ },
+ "provider": "claude",
+ "model": "claude-sonnet-4-5-20250929",
+ "fallback_used": false,
+ "tokens_used": null,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_en_complaint_001"
+ "request_id": "req_nw_en_praise_001abc"
}
```
-
+
```bash
curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
- -d '{"text": "What camera and lens setup are you using for these shots?", "platform": "youtube"}'
+ -d '{"text": "The audio quality is terrible in this one. Can barely hear anything after the 5 minute mark.", "platform": "youtube"}'
```
Response:
@@ -219,30 +275,36 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "What camera and lens setup are you using for these shots?",
- "intent": "question",
- "intent_confidence": 0.97,
- "sentiment": "neutral",
- "sentiment_confidence": 0.92,
+ "id": "cls_nw_d4e5f6a7b8c9",
+ "object": "classification",
+ "intent": ["complaint"],
+ "sentiment": "negative",
+ "language": "en",
"dialect": null,
"dialect_confidence": null,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "en",
- "model": "claude-v1",
- "cached": false
+ "requires_response": true,
+ "priority": "high",
+ "suggested_reply": {
+ "text": "",
+ "direction": "ltr"
+ },
+ "provider": "claude",
+ "model": "claude-sonnet-4-5-20250929",
+ "fallback_used": false,
+ "tokens_used": null,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_en_question_001"
+ "request_id": "req_nw_en_complaint_001"
}
```
-
+
```bash
curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{"text": "ما شاء الله عليك، محتوى رهيب!", "platform": "youtube"}'
```
@@ -252,30 +314,36 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "ما شاء الله عليك، محتوى رهيب!",
- "intent": "praise",
- "intent_confidence": 0.98,
+ "id": "cls_nw_e5f6a7b8c9d0",
+ "object": "classification",
+ "intent": ["praise"],
"sentiment": "positive",
- "sentiment_confidence": 0.97,
+ "language": "ar",
"dialect": "gulf",
"dialect_confidence": 0.93,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "ar",
- "model": "nagl-v1",
- "cached": false
+ "requires_response": false,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "",
+ "direction": "rtl"
+ },
+ "provider": "allam",
+ "model": "allam-13b",
+ "fallback_used": false,
+ "tokens_used": null,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_ghi789jkl012"
+ "request_id": "req_nw_ghi789jkl012ab"
}
```
-
+
```bash
curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{"text": "الصوت وحش أوي في الفيديو ده", "platform": "youtube"}'
```
@@ -285,30 +353,36 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "الصوت وحش أوي في الفيديو ده",
- "intent": "complaint",
- "intent_confidence": 0.94,
+ "id": "cls_nw_f6a7b8c9d0e1",
+ "object": "classification",
+ "intent": ["complaint"],
"sentiment": "negative",
- "sentiment_confidence": 0.96,
+ "language": "ar",
"dialect": "egyptian",
"dialect_confidence": 0.97,
- "toxicity": "none",
- "toxicity_confidence": 0.95,
- "categories": ["feedback"],
- "language": "ar",
- "model": "nagl-v1",
- "cached": false
+ "requires_response": true,
+ "priority": "high",
+ "suggested_reply": {
+ "text": "",
+ "direction": "rtl"
+ },
+ "provider": "allam",
+ "model": "allam-13b",
+ "fallback_used": false,
+ "tokens_used": null,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_mno345pqr678"
+ "request_id": "req_nw_mno345pqr678ab"
}
```
-
+
```bash
curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{"text": "لو سمحت حاول تحكي عن المطاعم بلبنان", "platform": "instagram"}'
```
@@ -318,22 +392,28 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "لو سمحت حاول تحكي عن المطاعم بلبنان",
- "intent": "suggestion",
- "intent_confidence": 0.92,
+ "id": "cls_nw_a7b8c9d0e1f2",
+ "object": "classification",
+ "intent": ["suggestion"],
"sentiment": "neutral",
- "sentiment_confidence": 0.88,
+ "language": "ar",
"dialect": "levantine",
"dialect_confidence": 0.96,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "ar",
- "model": "nagl-v1",
- "cached": false
+ "requires_response": true,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "",
+ "direction": "rtl"
+ },
+ "provider": "allam",
+ "model": "allam-13b",
+ "fallback_used": false,
+ "tokens_used": null,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_stu901vwx234"
+ "request_id": "req_nw_stu901vwx234ab"
}
```
diff --git a/api-reference/comments-reply.mdx b/api-reference/comments-reply.mdx
index d6321d7..352dc9c 100644
--- a/api-reference/comments-reply.mdx
+++ b/api-reference/comments-reply.mdx
@@ -1,62 +1,82 @@
---
-title: "Reply to Comment"
-sidebarTitle: "POST /v1/comments/:id/reply"
-description: "Generate a context-aware reply to a comment in Arabic or English."
-api: "POST https://api.trynawa.com/v1/comments/{id}/reply"
+title: "Classify and reply"
+sidebarTitle: "POST /v1/comments/reply"
+description: "Classify a comment and generate a contextual reply in a single call."
+api: "POST https://api.trynawa.com/v1/comments/reply"
---
-Generate an AI-powered reply that matches the commenter's language and cultural context. For Arabic comments, replies match the detected dialect (Gulf, Egyptian, Levantine, MSA). For English comments, replies are natural and platform-appropriate. Language is auto-detected unless overridden.
+Classify a comment and generate a context-aware reply in a single call. Replies match the commenter's language, dialect, and script style.
+
+For **Arabizi input** (Latin-script Arabic like `7abibi`, `shu ra2yak`), NAWA automatically detects the script and forces Claude as the reply provider. This ensures replies come back in matching Latin-script Arabizi rather than Arabic script.
+
+For **Arabic-script input**, replies are generated in the same dialect and script. For **English input**, replies are natural and platform-appropriate.
- Cost: **$0.008** per request (8 credits). Semantic cache hits are free (`X-NAWA-Cache: HIT`).
+ Cost: **$0.008** per request (8 credits). This includes both classification and reply generation.
## Request
-### Path parameters
+### Headers
+
+| Header | Required | Description |
+|--------|----------|-------------|
+| `Authorization` | Yes | `Bearer nawa_live_sk_xxx` or `Bearer nawa_test_sk_xxx` |
+| `Content-Type` | Yes | `application/json` |
+
+### Query parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
-| `id` | string | Yes | The comment ID to reply to. |
+| `provider` | string | No | Force a specific AI provider for classification: `claude`, `gemini`, `allam`. For Arabizi input, reply generation always uses Claude regardless of this parameter. |
### Body parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
-| `tone` | string | No | Reply tone: `friendly`, `professional`, `casual`, `formal`. Default: `friendly`. |
-| `max_length` | integer | No | Maximum reply length in characters. Default: 500. |
-| `context` | string | No | Additional context about the channel or video to improve reply relevance. |
-| `language` | string | No | Force reply language: `ar`, `en`, `auto`. Default: `auto` (matches commenter's language). |
+| `text` | string | Yes | Comment text to classify and reply to. Supports Arabic script, Arabizi, and English. |
+| `tone` | string | No | Reply tone: `friendly`, `professional`, `casual`, `formal`. Default: `professional`. |
+| `max_length` | integer | No | Maximum reply length in characters (1-2000). Default: `500`. |
### Example request
```bash cURL
-curl -X POST https://api.trynawa.com/v1/comments/cmt_abc123/reply \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+curl -X POST https://api.trynawa.com/v1/comments/reply \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
+ "text": "shu ra2yak fi el beat? ana b7eb el vibe kter",
"tone": "friendly",
- "context": "Tech review channel focused on smartphones"
+ "max_length": 500
}'
```
-```typescript TypeScript
-const { data, error } = await nawa.comments.reply('cmt_abc123', {
- tone: 'friendly',
- context: 'Tech review channel focused on smartphones'
-})
-```
-
```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="nawa_live_sk_xxx")
+
result = nawa.comments.reply(
- comment_id="cmt_abc123",
+ text="shu ra2yak fi el beat? ana b7eb el vibe kter",
tone="friendly",
- context="Tech review channel focused on smartphones"
+ max_length=500,
)
```
+```typescript TypeScript
+import { Nawa } from '@nawalabs/sdk'
+
+const nawa = new Nawa({ apiKey: process.env.NAWA_API_KEY })
+
+const { data, error } = await nawa.comments.reply({
+ text: 'shu ra2yak fi el beat? ana b7eb el vibe kter',
+ tone: 'friendly',
+ maxLength: 500
+})
+```
+
## Response
@@ -67,25 +87,197 @@ result = nawa.comments.reply(
{
"success": true,
"result": {
- "comment_id": "cmt_abc123",
- "reply_text": "إن شاء الله الجزء الثاني قريب! تابعنا عشان ما يفوتك 🔔",
- "reply_dialect": "gulf",
- "tone": "friendly",
- "original_intent": "question",
- "original_dialect": "gulf"
+ "id": "rpl_nw_a1b2c3d4e5f6",
+ "object": "comment_reply",
+ "classification": {
+ "intent": ["question"],
+ "sentiment": "positive",
+ "priority": "medium",
+ "requires_response": true
+ },
+ "reply": {
+ "text": "ahlan! el beat 7elo kter, glad you like the vibe",
+ "direction": "ltr",
+ "tone": "friendly"
+ },
+ "provider": "claude",
+ "model": "claude-sonnet-4-5-20250929",
+ "cost_usd": 0.008,
+ "credits_used": 8
},
"errors": [],
- "request_id": "req_rep789xyz012"
+ "request_id": "req_nw_rpl1a2b3c4d5e6f7"
}
```
+### Response headers
+
+| Header | Description |
+|--------|-------------|
+| `X-Request-Id` | Unique request identifier for debugging |
+| `X-NAWA-Provider` | AI provider that generated the reply |
+| `X-RateLimit-Limit` | Rate limit ceiling for current window |
+| `X-RateLimit-Remaining` | Requests remaining in current window |
+| `X-RateLimit-Reset` | Window reset time (RFC 3339) |
+
### Result fields
| Field | Type | Description |
|-------|------|-------------|
-| `comment_id` | string | The comment that was replied to |
-| `reply_text` | string | The generated reply text |
-| `reply_dialect` | string \| null | Dialect used in the reply (matches original). `null` for English replies. |
-| `tone` | string | The tone used for the reply |
-| `original_intent` | string | Detected intent of the original comment |
-| `original_dialect` | string | Detected dialect of the original comment |
+| `id` | string | Reply ID in `rpl_nw_xxx` format |
+| `object` | string | Always `"comment_reply"` |
+| `classification.intent` | string[] | Detected intents of the original comment |
+| `classification.sentiment` | string | `positive`, `negative`, `neutral`, or `mixed` |
+| `classification.priority` | string | `high`, `medium`, or `low` |
+| `classification.requires_response` | boolean | Whether the comment warrants a reply |
+| `reply.text` | string | Generated reply text. Empty string if `requires_response` is `false`. |
+| `reply.direction` | string | `rtl` if the reply contains Arabic script, `ltr` otherwise |
+| `reply.tone` | string | The tone used for the reply |
+| `provider` | string | AI provider that generated the reply |
+| `model` | string | Model identifier |
+| `cost_usd` | number | Cost in USD |
+| `credits_used` | integer | Credits consumed |
+
+### Error responses
+
+| Status | Type | When |
+|--------|------|------|
+| 400 | `invalid_request_error` | Missing `text`, invalid `tone`, `max_length` out of range, invalid `provider` |
+| 401 | `authentication_error` | Invalid or missing API key |
+| 402 | `permission_error` | No credits remaining |
+| 429 | `rate_limit_error` | Rate limit exceeded |
+| 500 | `api_error` | Internal or provider error |
+
+## Arabizi reply behavior
+
+When NAWA detects Arabizi input, reply generation is handled differently:
+
+1. **Classification** proceeds normally through the language-based router (typically ALLaM for Arabic content)
+2. **Reply generation** forces Claude regardless of classification provider, because only Claude follows the Arabizi script mirror hint
+3. The reply comes back in **Latin-script Arabizi** matching the commenter's style (using number substitutions like `7` for ح and `3` for ع)
+
+If the comment is classified as not requiring a response (e.g., simple praise), `reply.text` is an empty string and `requires_response` is `false`.
+
+### More examples
+
+
+
+ ```bash
+ curl -X POST https://api.trynawa.com/v1/comments/reply \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "text": "هذا المنتج سيء جداً ولا أنصح به",
+ "tone": "professional"
+ }'
+ ```
+
+ Response:
+ ```json
+ {
+ "success": true,
+ "result": {
+ "id": "rpl_nw_b2c3d4e5f6a7",
+ "object": "comment_reply",
+ "classification": {
+ "intent": ["complaint"],
+ "sentiment": "negative",
+ "priority": "high",
+ "requires_response": true
+ },
+ "reply": {
+ "text": "نعتذر عن هذه التجربة. نود مساعدتك في حل المشكلة.",
+ "direction": "rtl",
+ "tone": "professional"
+ },
+ "provider": "allam",
+ "model": "allam-13b",
+ "cost_usd": 0.008,
+ "credits_used": 8
+ },
+ "errors": [],
+ "request_id": "req_nw_rpl2b3c4d5e6f7a8"
+ }
+ ```
+
+
+
+ ```bash
+ curl -X POST https://api.trynawa.com/v1/comments/reply \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "text": "wallah a7san video, y3afech 3la hal content",
+ "tone": "friendly"
+ }'
+ ```
+
+ Response:
+ ```json
+ {
+ "success": true,
+ "result": {
+ "id": "rpl_nw_c3d4e5f6a7b8",
+ "object": "comment_reply",
+ "classification": {
+ "intent": ["praise"],
+ "sentiment": "positive",
+ "priority": "medium",
+ "requires_response": false
+ },
+ "reply": {
+ "text": "",
+ "direction": "ltr",
+ "tone": "friendly"
+ },
+ "provider": "allam",
+ "model": "allam-13b",
+ "cost_usd": 0.008,
+ "credits_used": 8
+ },
+ "errors": [],
+ "request_id": "req_nw_rpl3c4d5e6f7a8b9"
+ }
+ ```
+
+
+
+ ```bash
+ curl -X POST https://api.trynawa.com/v1/comments/reply \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "text": "What camera setup are you using for these shots?",
+ "tone": "casual"
+ }'
+ ```
+
+ Response:
+ ```json
+ {
+ "success": true,
+ "result": {
+ "id": "rpl_nw_d4e5f6a7b8c9",
+ "object": "comment_reply",
+ "classification": {
+ "intent": ["question"],
+ "sentiment": "neutral",
+ "priority": "medium",
+ "requires_response": true
+ },
+ "reply": {
+ "text": "Hey! I'm using a Sony A7IV with a 24-70mm f/2.8 lens for most shots.",
+ "direction": "ltr",
+ "tone": "casual"
+ },
+ "provider": "claude",
+ "model": "claude-sonnet-4-5-20250929",
+ "cost_usd": 0.008,
+ "credits_used": 8
+ },
+ "errors": [],
+ "request_id": "req_nw_rpl4d5e6f7a8b9c0"
+ }
+ ```
+
+
diff --git a/api-reference/rubric-classify.mdx b/api-reference/rubric-classify.mdx
index 4489175..445b59a 100644
--- a/api-reference/rubric-classify.mdx
+++ b/api-reference/rubric-classify.mdx
@@ -1,83 +1,104 @@
---
-title: "Rubric Classify"
-sidebarTitle: "POST /v1/rubric/classify"
-description: "Classify a comment against a custom rubric with predefined scoring criteria."
-api: "POST https://api.trynawa.com/v1/rubric/classify"
+title: "Rubric classify"
+sidebarTitle: "POST /v1/rubric-classify"
+description: "Classify text against a custom rubric with user-defined categories and scoring criteria."
+api: "POST https://api.trynawa.com/v1/rubric-classify"
---
-Classify a comment against a custom rubric. Define your own categories and scoring criteria for domain-specific classification.
+Classify text against a custom rubric. Define your own categories with optional descriptions for domain-specific classification. Supports multi-label classification and configurable confidence thresholds.
- Cost: **$0.003** per request (3 credits). **500 free requests/month** on this endpoint -- no credit card required. Semantic cache hits are free (`X-NAWA-Cache: HIT`).
+ Cost: **$0.003** per request (3 credits).
## Request
+### Headers
+
+| Header | Required | Description |
+|--------|----------|-------------|
+| `Authorization` | Yes | `Bearer nawa_live_sk_xxx` or `Bearer nawa_test_sk_xxx` |
+| `Content-Type` | Yes | `application/json` |
+
+### Query parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `provider` | string | No | Force a specific AI provider: `claude`, `gemini`, `allam`. Bypasses automatic language-based routing. |
+
### Body parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `text` | string | Yes | The comment text to classify. Max 5,000 characters. |
-| `rubric` | object | Yes | The rubric definition with categories and criteria. |
-| `rubric.categories` | string[] | Yes | List of category names to classify against. |
-| `rubric.descriptions` | object | No | Category descriptions to guide the model. Keys are category names, values are description strings. |
-| `platform` | string | No | Source platform for context. |
+| `rubric` | object | Yes | The rubric definition with categories and scoring criteria. |
+| `rubric.categories` | array | Yes | Array of category objects (max 20). Each object requires a `name` field and accepts an optional `description` field. |
+| `rubric.multi_label` | boolean | No | When `true`, returns all categories above the confidence threshold. Default: `false` (single best match). |
+| `rubric.confidence_threshold` | number | No | Minimum confidence (0-1) for a category to appear in results. Default: `0.5`. |
### Example request
```bash cURL
-curl -X POST https://api.trynawa.com/v1/rubric/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+curl -X POST https://api.trynawa.com/v1/rubric-classify \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"text": "وين الترجمة العربية؟ مافهمت شي",
"rubric": {
- "categories": ["translation_request", "technical_issue", "content_feedback", "off_topic"],
- "descriptions": {
- "translation_request": "User is asking for subtitles or translation",
- "technical_issue": "Audio, video, or playback problems",
- "content_feedback": "Comments about the content quality",
- "off_topic": "Not related to the video"
- }
- },
- "platform": "youtube"
- }'
-```
-
-```typescript TypeScript
-const { data, error } = await nawa.rubric.classify({
- text: 'وين الترجمة العربية؟ مافهمت شي',
- rubric: {
- categories: ['translation_request', 'technical_issue', 'content_feedback', 'off_topic'],
- descriptions: {
- translation_request: 'User is asking for subtitles or translation',
- technical_issue: 'Audio, video, or playback problems',
- content_feedback: 'Comments about the content quality',
- off_topic: 'Not related to the video'
+ "categories": [
+ {"name": "translation_request", "description": "User is asking for subtitles or translation"},
+ {"name": "technical_issue", "description": "Audio, video, or playback problems"},
+ {"name": "content_feedback", "description": "Comments about the content quality"},
+ {"name": "off_topic", "description": "Not related to the video"}
+ ],
+ "multi_label": false,
+ "confidence_threshold": 0.5
}
- },
- platform: 'youtube'
-})
+ }'
```
```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="nawa_live_sk_xxx")
+
result = nawa.rubric.classify(
text="وين الترجمة العربية؟ مافهمت شي",
rubric={
- "categories": ["translation_request", "technical_issue", "content_feedback", "off_topic"],
- "descriptions": {
- "translation_request": "User is asking for subtitles or translation",
- "technical_issue": "Audio, video, or playback problems",
- "content_feedback": "Comments about the content quality",
- "off_topic": "Not related to the video",
- },
+ "categories": [
+ {"name": "translation_request", "description": "User is asking for subtitles or translation"},
+ {"name": "technical_issue", "description": "Audio, video, or playback problems"},
+ {"name": "content_feedback", "description": "Comments about the content quality"},
+ {"name": "off_topic", "description": "Not related to the video"},
+ ],
+ "multi_label": False,
+ "confidence_threshold": 0.5,
},
- platform="youtube",
)
```
+```typescript TypeScript
+import { Nawa } from '@nawalabs/sdk'
+
+const nawa = new Nawa({ apiKey: process.env.NAWA_API_KEY })
+
+const { data, error } = await nawa.rubric.classify({
+ text: 'وين الترجمة العربية؟ مافهمت شي',
+ rubric: {
+ categories: [
+ { name: 'translation_request', description: 'User is asking for subtitles or translation' },
+ { name: 'technical_issue', description: 'Audio, video, or playback problems' },
+ { name: 'content_feedback', description: 'Comments about the content quality' },
+ { name: 'off_topic', description: 'Not related to the video' }
+ ],
+ multiLabel: false,
+ confidenceThreshold: 0.5
+ }
+})
+```
+
## Response
@@ -88,34 +109,103 @@ result = nawa.rubric.classify(
{
"success": true,
"result": {
- "text": "وين الترجمة العربية؟ مافهمت شي",
- "category": "translation_request",
- "category_confidence": 0.94,
- "scores": {
- "translation_request": 0.94,
- "technical_issue": 0.03,
- "content_feedback": 0.02,
- "off_topic": 0.01
- },
- "dialect": "gulf",
- "dialect_confidence": 0.91,
+ "id": "rcl_nw_a1b2c3d4e5f6",
+ "object": "rubric_classification",
+ "categories": [
+ {"name": "translation_request", "confidence": 0.94}
+ ],
+ "multi_label": false,
"language": "ar",
- "model": "nagl-v1",
- "cached": false
+ "provider": "allam",
+ "model": "allam-13b",
+ "fallback_used": false,
+ "cost_usd": 0.003,
+ "credits_used": 3
},
"errors": [],
- "request_id": "req_rub123abc456"
+ "request_id": "req_nw_rub123abc456def7"
}
```
+### Response headers
+
+| Header | Description |
+|--------|-------------|
+| `X-Request-Id` | Unique request identifier for debugging |
+| `X-NAWA-Provider` | AI provider used (`allam`, `claude`, or `gemini`) |
+| `X-RateLimit-Limit` | Rate limit ceiling for current window |
+| `X-RateLimit-Remaining` | Requests remaining in current window |
+| `X-RateLimit-Reset` | Window reset time (RFC 3339) |
+
### Result fields
| Field | Type | Description |
|-------|------|-------------|
-| `category` | string | The top matching category from your rubric |
-| `category_confidence` | number | Confidence score (0–1) for the top category |
-| `scores` | object | Confidence scores for all rubric categories |
-| `dialect` | string | Detected Arabic dialect |
-| `dialect_confidence` | number | Dialect confidence score (0–1) |
-| `language` | string | Detected language code |
-| `cached` | boolean | Whether served from semantic cache |
+| `id` | string | Rubric classification ID in `rcl_nw_xxx` format |
+| `object` | string | Always `"rubric_classification"` |
+| `categories` | array | Matched categories with confidence scores, filtered by the threshold |
+| `categories[].name` | string | Category name from your rubric |
+| `categories[].confidence` | number | Confidence score (0-1, rounded to 2 decimal places) |
+| `multi_label` | boolean | Whether multi-label mode was used |
+| `language` | string | Detected language: `ar`, `en`, or `mixed` |
+| `provider` | string | AI provider used: `allam`, `claude`, or `gemini` |
+| `model` | string | Model identifier |
+| `fallback_used` | boolean | Whether a fallback provider was used |
+| `cost_usd` | number | Cost in USD |
+| `credits_used` | integer | Credits consumed |
+
+### Error responses
+
+| Status | Type | When |
+|--------|------|------|
+| 400 | `invalid_request_error` | Missing `text` or `rubric`, empty categories, categories exceed 20, missing category `name`, invalid `provider` |
+| 401 | `authentication_error` | Invalid or missing API key |
+| 402 | `permission_error` | No credits remaining |
+| 429 | `rate_limit_error` | Rate limit exceeded |
+| 500 | `api_error` | Internal or provider error |
+
+### Multi-label example
+
+When `multi_label` is `true`, all categories that meet the confidence threshold are returned:
+
+```bash
+curl -X POST https://api.trynawa.com/v1/rubric-classify \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "text": "الصوت مو واضح وأبي ترجمة عربية لو سمحت",
+ "rubric": {
+ "categories": [
+ {"name": "translation_request"},
+ {"name": "technical_issue"},
+ {"name": "content_feedback"}
+ ],
+ "multi_label": true,
+ "confidence_threshold": 0.3
+ }
+ }'
+```
+
+Response:
+```json
+{
+ "success": true,
+ "result": {
+ "id": "rcl_nw_b2c3d4e5f6a7",
+ "object": "rubric_classification",
+ "categories": [
+ {"name": "translation_request", "confidence": 0.82},
+ {"name": "technical_issue", "confidence": 0.71}
+ ],
+ "multi_label": true,
+ "language": "ar",
+ "provider": "allam",
+ "model": "allam-13b",
+ "fallback_used": false,
+ "cost_usd": 0.003,
+ "credits_used": 3
+ },
+ "errors": [],
+ "request_id": "req_nw_rub789ghi012jkl3"
+}
+```
diff --git a/openapi.yaml b/openapi.yaml
index 17706f2..7ca77c1 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -53,12 +53,23 @@ paths:
operationId: classify
summary: Classify text
description: |
- Classify Arabic or English text. Returns intent, sentiment, dialect, toxicity,
- and categories in a single API call. Supports semantic caching.
+ Classify Arabic or English text. Returns intent, sentiment, dialect, priority,
+ and a suggested reply direction. Supports semantic caching and per-user calibration.
+
+ Arabic text (including Arabizi) is routed to ALLaM. English text is routed to Claude.
+ Use the `provider` query parameter to override routing for A/B testing.
tags: [Classification]
x-nawa-cost: "$0.006"
x-nawa-cache: true
x-nawa-free: false
+ parameters:
+ - name: provider
+ in: query
+ required: false
+ description: Force a specific AI provider for A/B testing. Bypasses language-based routing.
+ schema:
+ type: string
+ enum: [claude, gemini, allam]
requestBody:
required: true
content:
@@ -71,10 +82,11 @@ paths:
type: string
minLength: 1
maxLength: 5000
- description: The comment text to classify
+ description: The comment text to classify. Supports Arabic script, Arabizi (Latin-script Arabic), and English.
examples:
- "متى الجزء الثاني؟"
- "ما شاء الله عليك، محتوى رهيب!"
+ - "9ba7oooo ya 7abibi el video 7elo kter"
platform:
type: string
enum: [youtube, instagram, twitter, facebook]
@@ -117,21 +129,51 @@ paths:
value:
success: true
result:
- text: "متى الجزء الثاني؟"
- intent: question
- intent_confidence: 0.97
+ id: cls_nw_a1b2c3d4e5f6
+ object: classification
+ intent: ["question"]
sentiment: neutral
- sentiment_confidence: 0.91
+ language: ar
dialect: gulf
dialect_confidence: 0.95
- toxicity: none
- toxicity_confidence: 0.99
- categories: ["engagement"]
- language: ar
- model: nagl-v1
- cached: false
+ requires_response: true
+ priority: medium
+ suggested_reply:
+ text: ""
+ direction: rtl
+ provider: allam
+ model: allam-13b
+ fallback_used: false
+ tokens_used: null
+ cost_usd: 0.006
+ credits_used: 6
errors: []
request_id: req_nw_a1b2c3d4e5f67890
+ arabizi_praise:
+ summary: Arabizi praise (Latin-script Arabic)
+ value:
+ success: true
+ result:
+ id: cls_nw_f7e8d9c0b1a2
+ object: classification
+ intent: ["praise"]
+ sentiment: positive
+ language: ar
+ dialect: gulf
+ dialect_confidence: 0.88
+ requires_response: false
+ priority: medium
+ suggested_reply:
+ text: ""
+ direction: rtl
+ provider: claude
+ model: arabizi-rubric
+ fallback_used: false
+ tokens_used: null
+ cost_usd: 0.006
+ credits_used: 6
+ errors: []
+ request_id: req_nw_b2c3d4e5f67890ab
"400":
$ref: "#/components/responses/BadRequest"
"401":
@@ -457,17 +499,26 @@ paths:
"500":
$ref: "#/components/responses/InternalError"
- /rubric/classify:
+ /rubric-classify:
post:
operationId: rubricClassify
summary: Classify with custom rubric
description: |
- Classify text against a user-defined rubric. Define your own categories and
- scoring criteria for domain-specific classification.
+ Classify text against a user-defined rubric. Define your own categories with
+ optional descriptions and scoring criteria for domain-specific classification.
+ Supports multi-label classification and configurable confidence thresholds.
tags: [Classification]
x-nawa-cost: "$0.003"
- x-nawa-cache: true
+ x-nawa-cache: false
x-nawa-free: false
+ parameters:
+ - name: provider
+ in: query
+ required: false
+ description: Force a specific AI provider for A/B testing. Bypasses language-based routing.
+ schema:
+ type: string
+ enum: [claude, gemini, allam]
requestBody:
required: true
content:
@@ -492,27 +543,40 @@ paths:
minItems: 1
maxItems: 20
items:
- type: string
- description: List of category names to classify against
- descriptions:
- type: object
- additionalProperties:
- type: string
- description: Category descriptions to guide the model
- platform:
- type: string
- enum: [youtube, instagram, twitter, facebook]
- description: Source platform for context
+ type: object
+ required: [name]
+ properties:
+ name:
+ type: string
+ description: Category name
+ description:
+ type: string
+ description: Category description to guide the model
+ description: List of categories to classify against (max 20)
+ multi_label:
+ type: boolean
+ default: false
+ description: "When `true`, returns all categories above the confidence threshold. When `false`, returns only the single best match."
+ confidence_threshold:
+ type: number
+ minimum: 0
+ maximum: 1
+ default: 0.5
+ description: Minimum confidence score for a category to be included in results
example:
text: "وين الترجمة العربية؟ مافهمت شي"
rubric:
- categories: ["translation_request", "technical_issue", "content_feedback", "off_topic"]
- descriptions:
- translation_request: "User is asking for subtitles or translation"
- technical_issue: "Audio, video, or playback problems"
- content_feedback: "Comments about the content quality"
- off_topic: "Not related to the video"
- platform: "youtube"
+ categories:
+ - name: "translation_request"
+ description: "User is asking for subtitles or translation"
+ - name: "technical_issue"
+ description: "Audio, video, or playback problems"
+ - name: "content_feedback"
+ description: "Comments about the content quality"
+ - name: "off_topic"
+ description: "Not related to the video"
+ multi_label: false
+ confidence_threshold: 0.5
responses:
"200":
description: Rubric classification result
@@ -521,10 +585,6 @@ paths:
$ref: "#/components/headers/X-Request-Id"
X-NAWA-Provider:
$ref: "#/components/headers/X-NAWA-Provider"
- X-NAWA-Cache:
- $ref: "#/components/headers/X-NAWA-Cache"
- X-NAWA-Balance:
- $ref: "#/components/headers/X-NAWA-Balance"
X-RateLimit-Limit:
$ref: "#/components/headers/X-RateLimit-Limit"
X-RateLimit-Remaining:
@@ -541,21 +601,22 @@ paths:
value:
success: true
result:
- text: "وين الترجمة العربية؟ مافهمت شي"
- category: translation_request
- category_confidence: 0.94
- scores:
- translation_request: 0.94
- technical_issue: 0.03
- content_feedback: 0.02
- off_topic: 0.01
- dialect: gulf
- dialect_confidence: 0.91
+ id: rcl_nw_a1b2c3d4e5f6
+ object: rubric_classification
+ categories:
+ - name: translation_request
+ confidence: 0.94
+ - name: technical_issue
+ confidence: 0.03
+ multi_label: false
language: ar
- model: nagl-v1
- cached: false
+ provider: allam
+ model: allam-13b
+ fallback_used: false
+ cost_usd: 0.003
+ credits_used: 3
errors: []
- request_id: req_rub123abc456
+ request_id: req_nw_rub123abc456def7
"400":
$ref: "#/components/responses/BadRequest"
"401":
@@ -567,37 +628,48 @@ paths:
"500":
$ref: "#/components/responses/InternalError"
- /comments/{id}/reply:
+ /comments/reply:
post:
- operationId: generateReply
- summary: Generate reply to comment
+ operationId: commentsReply
+ summary: Classify and generate reply
description: |
- Generate a culturally-aware, dialect-matched reply to an Arabic comment.
- Replies match the commenter's dialect and are contextually appropriate.
+ Classify a comment and generate a contextual reply in a single call.
+ Supports tone control and max length configuration.
+
+ For Arabizi (Latin-script Arabic like "7abibi", "shu ra2yak"), NAWA automatically
+ detects the script style and forces Claude as the reply provider to produce
+ matching Latin-script replies. Arabic-script comments are routed normally.
tags: [Reply]
x-nawa-cost: "$0.008"
- x-nawa-cache: true
+ x-nawa-cache: false
x-nawa-free: false
parameters:
- - name: id
- in: path
- required: true
- description: The comment ID to reply to
+ - name: provider
+ in: query
+ required: false
+ description: Force a specific AI provider for classification. For Arabizi input, reply generation always uses Claude regardless of this parameter.
schema:
type: string
- examples:
- - "cmt_abc123"
+ enum: [claude, gemini, allam]
requestBody:
- required: false
+ required: true
content:
application/json:
schema:
type: object
+ required: [text]
properties:
+ text:
+ type: string
+ minLength: 1
+ description: Comment text to classify and reply to. Supports Arabic script, Arabizi, and English.
+ examples:
+ - "هذا المنتج سيء جداً ولا أنصح به"
+ - "shu ra2yak fi el beat? ana b7eb el vibe kter"
tone:
type: string
enum: [friendly, professional, casual, formal]
- default: friendly
+ default: professional
description: Reply tone
max_length:
type: integer
@@ -605,29 +677,18 @@ paths:
maximum: 2000
default: 500
description: Maximum reply length in characters
- context:
- type: string
- description: Additional context about the channel or video
- language:
- type: string
- enum: [ar, en, auto]
- default: auto
- description: "Force reply language. Default: auto (matches commenter's language)."
example:
+ text: "shu ra2yak fi el beat? ana b7eb el vibe kter"
tone: "friendly"
- context: "Tech review channel focused on smartphones"
+ max_length: 500
responses:
"200":
- description: Generated reply
+ description: Classification and reply result
headers:
X-Request-Id:
$ref: "#/components/headers/X-Request-Id"
X-NAWA-Provider:
$ref: "#/components/headers/X-NAWA-Provider"
- X-NAWA-Cache:
- $ref: "#/components/headers/X-NAWA-Cache"
- X-NAWA-Balance:
- $ref: "#/components/headers/X-NAWA-Balance"
X-RateLimit-Limit:
$ref: "#/components/headers/X-RateLimit-Limit"
X-RateLimit-Remaining:
@@ -639,19 +700,50 @@ paths:
schema:
$ref: "#/components/schemas/ReplySuccessResponse"
examples:
- gulf_reply:
- summary: Friendly reply to Gulf Arabic question
+ arabizi_reply:
+ summary: Arabizi comment with Latin-script reply
value:
success: true
result:
- comment_id: cmt_abc123
- reply_text: "إن شاء الله الجزء الثاني قريب! تابعنا عشان ما يفوتك 🔔"
- reply_dialect: gulf
- tone: friendly
- original_intent: question
- original_dialect: gulf
+ id: rpl_nw_a1b2c3d4e5f6
+ object: comment_reply
+ classification:
+ intent: ["question"]
+ sentiment: positive
+ priority: medium
+ requires_response: true
+ reply:
+ text: "ahlan! el beat 7elo kter, glad you like the vibe"
+ direction: ltr
+ tone: friendly
+ provider: claude
+ model: claude-sonnet-4-5-20250929
+ cost_usd: 0.008
+ credits_used: 8
errors: []
- request_id: req_rep789xyz012
+ request_id: req_nw_rpl1a2b3c4d5e6f7
+ arabic_reply:
+ summary: Arabic comment with Arabic reply
+ value:
+ success: true
+ result:
+ id: rpl_nw_b2c3d4e5f6a7
+ object: comment_reply
+ classification:
+ intent: ["complaint"]
+ sentiment: negative
+ priority: high
+ requires_response: true
+ reply:
+ text: "نعتذر عن هذه التجربة. نود مساعدتك في حل المشكلة."
+ direction: rtl
+ tone: professional
+ provider: allam
+ model: allam-13b
+ cost_usd: 0.008
+ credits_used: 8
+ errors: []
+ request_id: req_nw_rpl2b3c4d5e6f7a8
"400":
$ref: "#/components/responses/BadRequest"
"401":
@@ -1170,7 +1262,7 @@ components:
description: AI provider used for this request
schema:
type: string
- enum: [allam, claude]
+ enum: [allam, claude, gemini]
X-NAWA-Cache:
description: Whether the response was served from semantic cache
schema:
@@ -1424,51 +1516,72 @@ components:
ClassificationResult:
type: object
+ required: [id, object, intent, sentiment, language, requires_response, priority, provider, model, cost_usd, credits_used]
properties:
- text:
+ id:
type: string
- description: The original input text
- intent:
+ description: Classification ID (`cls_nw_xxx` format)
+ examples: [cls_nw_a1b2c3d4e5f6]
+ object:
type: string
- enum: [question, complaint, praise, suggestion, spam, other]
- description: Detected intent
- intent_confidence:
- type: number
- minimum: 0
- maximum: 1
+ const: classification
+ intent:
+ type: array
+ items:
+ type: string
+ description: Detected intents (e.g. `["praise"]`, `["question", "complaint"]`)
sentiment:
type: string
enum: [positive, negative, neutral, mixed]
- sentiment_confidence:
- type: number
- minimum: 0
- maximum: 1
+ language:
+ type: string
+ enum: [ar, en, mixed]
dialect:
type: string
- enum: [gulf, egyptian, levantine, msa]
+ nullable: true
+ description: Arabic dialect (`gulf`, `egyptian`, `levantine`, `maghrebi`, `msa`). Null for English text.
dialect_confidence:
type: number
+ nullable: true
minimum: 0
maximum: 1
- toxicity:
+ description: Dialect confidence (0-1). Null for English text.
+ requires_response:
+ type: boolean
+ description: Whether this comment needs a reply
+ priority:
type: string
- enum: [none, mild, moderate, severe]
- toxicity_confidence:
- type: number
- minimum: 0
- maximum: 1
- categories:
- type: array
- items:
- type: string
- description: "Content categories: engagement, support, feedback, spam"
- language:
+ enum: [high, medium, low]
+ suggested_reply:
+ type: object
+ properties:
+ text:
+ type: string
+ description: Reply direction summary (may be empty)
+ direction:
+ type: string
+ enum: [ltr, rtl]
+ description: Text direction based on detected language
+ provider:
type: string
- enum: [ar, en, mixed]
+ enum: [claude, gemini, allam]
+ description: AI provider used for classification
model:
type: string
- cached:
+ description: "Model identifier (e.g. `allam-13b`, `claude-sonnet-4-5-20250929`, `arabizi-rubric`)"
+ fallback_used:
type: boolean
+ description: Whether a fallback provider was used
+ tokens_used:
+ type: integer
+ nullable: true
+ description: Token count (currently always null)
+ cost_usd:
+ type: number
+ description: Cost in USD (always 0.006)
+ credits_used:
+ type: integer
+ description: Credits consumed (always 6)
TranslateResult:
type: object
@@ -1550,8 +1663,8 @@ components:
description: Confidence score for dialect detection. Null if not Arabic.
script:
type: string
- enum: [arabic, latin, mixed]
- description: Script type
+ enum: [arabic, latin, arabizi, mixed]
+ description: "Script type. `arabizi` indicates Latin-script Arabic (e.g. `7abibi`, `shu`)."
text_direction:
type: string
enum: [rtl, ltr]
@@ -1687,62 +1800,110 @@ components:
RubricResult:
type: object
+ required: [id, object, categories, multi_label, language, provider, model, cost_usd, credits_used]
properties:
- text:
- type: string
- description: The original input text
- category:
+ id:
type: string
- description: The top matching category from the rubric
- category_confidence:
- type: number
- minimum: 0
- maximum: 1
- scores:
- type: object
- additionalProperties:
- type: number
- description: Confidence scores for all rubric categories
- dialect:
+ description: Rubric classification ID (`rcl_nw_xxx` format)
+ examples: [rcl_nw_a1b2c3d4e5f6]
+ object:
type: string
- enum: [gulf, egyptian, levantine, msa]
- dialect_confidence:
- type: number
- minimum: 0
- maximum: 1
+ const: rubric_classification
+ categories:
+ type: array
+ items:
+ type: object
+ required: [name, confidence]
+ properties:
+ name:
+ type: string
+ description: Category name from the rubric
+ confidence:
+ type: number
+ minimum: 0
+ maximum: 1
+ description: Confidence score (rounded to 2 decimal places)
+ description: Matched categories with confidence scores, filtered by the confidence threshold
+ multi_label:
+ type: boolean
+ description: Whether multi-label classification was used
language:
type: string
enum: [ar, en, mixed]
+ provider:
+ type: string
+ enum: [claude, gemini, allam]
+ description: AI provider used
model:
type: string
- cached:
+ description: Model identifier
+ fallback_used:
type: boolean
+ description: Whether a fallback provider was used
+ cost_usd:
+ type: number
+ description: Cost in USD (always 0.003)
+ credits_used:
+ type: integer
+ description: Credits consumed (always 3)
ReplyResult:
type: object
+ required: [id, object, classification, reply, provider, model, cost_usd, credits_used]
properties:
- comment_id:
- type: string
- description: The comment that was replied to
- reply_text:
- type: string
- description: The generated reply text
- reply_dialect:
+ id:
type: string
- enum: [gulf, egyptian, levantine, msa]
- description: Dialect used in the reply
- tone:
+ description: Reply ID (`rpl_nw_xxx` format)
+ examples: [rpl_nw_a1b2c3d4e5f6]
+ object:
type: string
- enum: [friendly, professional, casual, formal]
- description: The tone used for the reply
- original_intent:
+ const: comment_reply
+ classification:
+ type: object
+ description: Classification of the input comment
+ properties:
+ intent:
+ type: array
+ items:
+ type: string
+ description: Detected intents
+ sentiment:
+ type: string
+ enum: [positive, negative, neutral, mixed]
+ priority:
+ type: string
+ enum: [high, medium, low]
+ requires_response:
+ type: boolean
+ description: Whether the comment warrants a reply
+ reply:
+ type: object
+ description: The generated reply
+ properties:
+ text:
+ type: string
+ description: "Generated reply text. Empty string if `requires_response` is `false`."
+ direction:
+ type: string
+ enum: [ltr, rtl]
+ description: Text direction based on the reply content
+ tone:
+ type: string
+ enum: [friendly, professional, casual, formal]
+ description: Tone used for the reply
+ provider:
type: string
- enum: [question, complaint, praise, suggestion, spam, other]
- description: Detected intent of the original comment
- original_dialect:
+ enum: [claude, gemini, allam]
+ description: AI provider that generated the reply
+ model:
type: string
- enum: [gulf, egyptian, levantine, msa]
- description: Detected dialect of the original comment
+ description: Model identifier
+ cost_usd:
+ type: number
+ description: Cost in USD (always 0.008)
+ credits_used:
+ type: integer
+ description: Credits consumed (always 8)
FeedbackInput:
type: object