diff --git a/api-reference/classify.mdx b/api-reference/classify.mdx
index ac3d730..79dde14 100644
--- a/api-reference/classify.mdx
+++ b/api-reference/classify.mdx
@@ -5,12 +5,12 @@ description: "Classify an Arabic or English comment by intent, sentiment, dialec
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 a suggested reply. Arabic comments are routed to HUMAIN's ALLaM model for dialect detection. English comments are routed to Claude for high-accuracy classification.
## Request
- 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`).
### Headers
@@ -20,27 +20,33 @@ 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`, or `allam`. Useful for A/B testing. |
+
### Body parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
-| `text` | string | Yes | The comment text to classify. 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. |
+| `text` | string | Yes | The comment text to classify. Min 1 character. |
+| `context` | object | No | Optional context object to improve classification accuracy. |
### Example request
```bash cURL
-curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+curl -X POST "https://api.trynawa.com/v1/classify" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"text": "متى الجزء الثاني؟",
- "platform": "youtube",
- "channel_id": "ch_123"
+ "context": {
+ "platform": "youtube",
+ "channel_id": "ch_123"
+ }
}'
```
@@ -51,9 +57,17 @@ const nawa = new Nawa({ apiKey: process.env.NAWA_API_KEY })
const { data, error } = await nawa.classify({
text: 'متى الجزء الثاني؟',
- platform: 'youtube',
- channelId: 'ch_123'
+ context: {
+ platform: 'youtube',
+ channelId: 'ch_123'
+ }
})
+
+if (data) {
+ console.log(data.intent) // ["question"]
+ console.log(data.dialect) // "gulf"
+ console.log(data.suggested_reply.text)
+}
```
```python Python
@@ -63,9 +77,15 @@ nawa = Nawa(api_key="your_api_key")
result = nawa.classify(
text="متى الجزء الثاني؟",
- platform="youtube",
- channel_id="ch_123"
+ context={
+ "platform": "youtube",
+ "channel_id": "ch_123"
+ }
)
+
+print(result.intent) # ["question"]
+print(result.dialect) # "gulf"
+print(result.suggested_reply.text)
```
@@ -78,22 +98,28 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "متى الجزء الثاني؟",
- "intent": "question",
- "intent_confidence": 0.97,
+ "id": "cls_nw_pon1yom9bkfe",
+ "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-v1",
+ "fallback_used": false,
+ "tokens_used": 142,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_abc123def456"
+ "request_id": "req_nw_abc123def456"
}
```
@@ -108,30 +134,37 @@ result = nawa.classify(
| `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) |
+| `X-NAWA-Provider` | AI provider used for this request |
+| `X-NAWA-Latency` | Server-side processing latency |
+| `X-NAWA-Calibration-Version` | Calibration threshold version applied |
### 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 | Unique classification ID (format: `cls_nw_xxx`) |
+| `object` | string | Always `"classification"` |
+| `intent` | string[] | Detected intents: `question`, `complaint`, `praise`, `suggestion`, `spam`, `other`. Can contain multiple values. |
+| `sentiment` | string | `positive`, `negative`, `neutral`, or `mixed` |
+| `language` | string | Detected language: `ar`, `en`, or `mixed` |
+| `dialect` | string or null | Arabic dialect: `gulf`, `egyptian`, `levantine`, `maghrebi`, or `msa`. Null for English text. |
+| `dialect_confidence` | number or null | Confidence score 0--1 for dialect detection. Null for English text. |
+| `requires_response` | boolean | Whether this comment warrants a reply |
+| `priority` | string | Response priority: `high`, `medium`, or `low` |
+| `suggested_reply.text` | string | AI-generated reply suggestion |
+| `suggested_reply.direction` | string | Text direction of the reply: `ltr` or `rtl` |
+| `provider` | string | AI provider used: `claude`, `gemini`, or `allam` |
+| `model` | string | Specific model version used |
+| `fallback_used` | boolean | Whether a fallback provider was used |
+| `tokens_used` | integer or null | Token count consumed by the AI call |
+| `cost_usd` | number | Cost of this request in USD |
+| `credits_used` | integer | Credits deducted from your balance |
### Error responses
| Status | Type | When |
|--------|------|------|
-| 400 | `invalid_request_error` | Missing `text`, invalid `platform`, text too long |
+| 400 | `invalid_request_error` | Missing `text` or text too short |
| 401 | `authentication_error` | Invalid or missing API key |
| 402 | `insufficient_credits` | No credits remaining |
| 429 | `rate_limit_error` | Rate limit exceeded |
@@ -143,9 +176,9 @@ result = nawa.classify(
```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": "This is hands down the best review I have seen on this phone. Subscribed!"}'
```
Response:
@@ -153,22 +186,28 @@ 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_en_praise_001",
+ "object": "classification",
+ "intent": ["praise"],
"sentiment": "positive",
- "sentiment_confidence": 0.98,
+ "language": "en",
"dialect": null,
"dialect_confidence": null,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "en",
+ "requires_response": true,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "Thanks so much! Really glad you found it helpful. More reviews coming soon!",
+ "direction": "ltr"
+ },
+ "provider": "claude",
"model": "claude-v1",
- "cached": false
+ "fallback_used": false,
+ "tokens_used": 98,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_en_praise_001"
+ "request_id": "req_nw_en_praise_001"
}
```
@@ -176,9 +215,9 @@ result = nawa.classify(
```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": "The audio quality is terrible in this one. Can barely hear anything after the 5 minute mark."}'
```
Response:
@@ -186,65 +225,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,
+ "id": "cls_nw_en_complaint_001",
+ "object": "classification",
+ "intent": ["complaint"],
"sentiment": "negative",
- "sentiment_confidence": 0.96,
- "dialect": null,
- "dialect_confidence": null,
- "toxicity": "none",
- "toxicity_confidence": 0.97,
- "categories": ["feedback"],
"language": "en",
- "model": "claude-v1",
- "cached": false
- },
- "errors": [],
- "request_id": "req_en_complaint_001"
- }
- ```
-
-
-
- ```bash
- curl -X POST https://api.trynawa.com/v1/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
- -H "Content-Type: application/json" \
- -d '{"text": "What camera and lens setup are you using for these shots?", "platform": "youtube"}'
- ```
-
- Response:
- ```json
- {
- "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,
"dialect": null,
"dialect_confidence": null,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "en",
+ "requires_response": true,
+ "priority": "high",
+ "suggested_reply": {
+ "text": "Sorry about the audio issue! We're looking into it. Thanks for letting us know the exact timestamp.",
+ "direction": "ltr"
+ },
+ "provider": "claude",
"model": "claude-v1",
- "cached": false
+ "fallback_used": false,
+ "tokens_used": 115,
+ "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"}'
+ -d '{"text": "ما شاء الله عليك، محتوى رهيب!"}'
```
Response:
@@ -252,32 +264,38 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "ما شاء الله عليك، محتوى رهيب!",
- "intent": "praise",
- "intent_confidence": 0.98,
+ "id": "cls_nw_gulf_praise_001",
+ "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": true,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "الله يبارك فيك! حياك الله ومشكور على الدعم 🙏",
+ "direction": "rtl"
+ },
+ "provider": "allam",
+ "model": "allam-v1",
+ "fallback_used": false,
+ "tokens_used": 130,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_ghi789jkl012"
+ "request_id": "req_nw_ghi789jkl012"
}
```
-
+
```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"}'
+ -d '{"text": "الصوت وحش أوي في الفيديو ده"}'
```
Response:
@@ -285,32 +303,38 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "الصوت وحش أوي في الفيديو ده",
- "intent": "complaint",
- "intent_confidence": 0.94,
+ "id": "cls_nw_egy_complaint_001",
+ "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-v1",
+ "fallback_used": false,
+ "tokens_used": 125,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_mno345pqr678"
+ "request_id": "req_nw_mno345pqr678"
}
```
-
+
```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"}'
+ -d '{"text": "Great video! But when is the next part coming out?"}'
```
Response:
@@ -318,23 +342,38 @@ result = nawa.classify(
{
"success": true,
"result": {
- "text": "لو سمحت حاول تحكي عن المطاعم بلبنان",
- "intent": "suggestion",
- "intent_confidence": 0.92,
- "sentiment": "neutral",
- "sentiment_confidence": 0.88,
- "dialect": "levantine",
- "dialect_confidence": 0.96,
- "toxicity": "none",
- "toxicity_confidence": 0.99,
- "categories": ["engagement"],
- "language": "ar",
- "model": "nagl-v1",
- "cached": false
+ "id": "cls_nw_multi_001",
+ "object": "classification",
+ "intent": ["praise", "question"],
+ "sentiment": "positive",
+ "language": "en",
+ "dialect": null,
+ "dialect_confidence": null,
+ "requires_response": true,
+ "priority": "medium",
+ "suggested_reply": {
+ "text": "Thank you! The next part is in the works -- stay tuned!",
+ "direction": "ltr"
+ },
+ "provider": "claude",
+ "model": "claude-v1",
+ "fallback_used": false,
+ "tokens_used": 105,
+ "cost_usd": 0.006,
+ "credits_used": 6
},
"errors": [],
- "request_id": "req_stu901vwx234"
+ "request_id": "req_nw_multi_001"
}
```
+
+
+ ```bash
+ curl -X POST "https://api.trynawa.com/v1/classify?provider=allam" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
+ -H "Content-Type: application/json" \
+ -d '{"text": "لو سمحت حاول تحكي عن المطاعم بلبنان"}'
+ ```
+
diff --git a/api-reference/comments-reply.mdx b/api-reference/comments-reply.mdx
index d6321d7..9cffc91 100644
--- a/api-reference/comments-reply.mdx
+++ b/api-reference/comments-reply.mdx
@@ -1,60 +1,95 @@
---
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"
+sidebarTitle: "POST /v1/comments/reply"
+description: "Classify a comment and generate a context-aware reply in a single API 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 an AI-powered reply in one request. For Arabic comments, replies match the detected dialect (Gulf, Egyptian, Levantine, MSA). For English comments, 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 endpoint performs classification and reply generation in a single call.
## 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: `claude`, `gemini`, or `allam`. |
### 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 | The comment text to reply to. Min 1 character. |
+| `tone` | string | No | Reply tone: `friendly`, `professional`, `casual`, `formal`. Default: `professional`. |
+| `max_length` | integer | No | Maximum reply length in characters (1--2000). Default: 500. |
+| `context.platform` | string | No | Source platform for context: `youtube`, `instagram`, `twitter`, `facebook`. |
+| `context.brand_voice` | string | No | Brand voice description to influence the reply tone. |
### 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": "متى الجزء الثاني؟",
"tone": "friendly",
- "context": "Tech review channel focused on smartphones"
+ "context": {
+ "platform": "youtube",
+ "brand_voice": "Tech review channel focused on smartphones"
+ }
}'
```
```typescript TypeScript
-const { data, error } = await nawa.comments.reply('cmt_abc123', {
+import { Nawa } from '@nawalabs/sdk'
+
+const nawa = new Nawa({ apiKey: process.env.NAWA_API_KEY })
+
+const { data, error } = await nawa.comments.reply({
+ text: 'متى الجزء الثاني؟',
tone: 'friendly',
- context: 'Tech review channel focused on smartphones'
+ context: {
+ platform: 'youtube',
+ brandVoice: 'Tech review channel focused on smartphones'
+ }
})
+
+if (data) {
+ console.log(data.reply.text)
+ console.log(data.classification.intent)
+}
```
```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="your_api_key")
+
result = nawa.comments.reply(
- comment_id="cmt_abc123",
+ text="متى الجزء الثاني؟",
tone="friendly",
- context="Tech review channel focused on smartphones"
+ context={
+ "platform": "youtube",
+ "brand_voice": "Tech review channel focused on smartphones"
+ }
)
+
+print(result.reply.text)
+print(result.classification.intent)
```
@@ -67,15 +102,26 @@ 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_pon1yom9bkfe",
+ "object": "comment_reply",
+ "classification": {
+ "intent": ["question"],
+ "sentiment": "neutral",
+ "priority": "medium",
+ "requires_response": true
+ },
+ "reply": {
+ "text": "إن شاء الله الجزء الثاني قريب! تابعنا عشان ما يفوتك 🔔",
+ "direction": "rtl",
+ "tone": "friendly"
+ },
+ "provider": "allam",
+ "model": "allam-v1",
+ "cost_usd": 0.008,
+ "credits_used": 8
},
"errors": [],
- "request_id": "req_rep789xyz012"
+ "request_id": "req_nw_rep789xyz012"
}
```
@@ -83,9 +129,87 @@ result = nawa.comments.reply(
| 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 | Unique reply ID (format: `rpl_nw_xxx`) |
+| `object` | string | Always `"comment_reply"` |
+| `classification.intent` | string[] | Detected intent(s) of the original comment |
+| `classification.sentiment` | string | Detected sentiment of the original comment |
+| `classification.priority` | string | Response priority: `high`, `medium`, or `low` |
+| `classification.requires_response` | boolean | Whether this comment warrants a reply |
+| `reply.text` | string | The generated reply text |
+| `reply.direction` | string | Text direction: `ltr` or `rtl` |
+| `reply.tone` | string | The tone applied to the reply |
+| `provider` | string | AI provider used: `claude`, `gemini`, or `allam` |
+| `model` | string | Specific model version used |
+| `cost_usd` | number | Cost of this request in USD |
+| `credits_used` | integer | Credits deducted from your balance |
+
+### Error responses
+
+| Status | Type | When |
+|--------|------|------|
+| 400 | `invalid_request_error` | Missing `text`, invalid `tone`, `max_length` out of range |
+| 401 | `authentication_error` | Invalid or missing API key |
+| 402 | `insufficient_credits` | No credits remaining |
+| 429 | `rate_limit_error` | Rate limit exceeded |
+| 500 | `api_error` | Internal or provider error |
+
+### 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": "The audio quality is terrible in this one.",
+ "tone": "professional",
+ "context": { "platform": "youtube" }
+ }'
+ ```
+
+ Response:
+ ```json
+ {
+ "success": true,
+ "result": {
+ "id": "rpl_nw_en_prof_001",
+ "object": "comment_reply",
+ "classification": {
+ "intent": ["complaint"],
+ "sentiment": "negative",
+ "priority": "high",
+ "requires_response": true
+ },
+ "reply": {
+ "text": "Thank you for the feedback. We've noted the audio issue and will improve it in upcoming videos.",
+ "direction": "ltr",
+ "tone": "professional"
+ },
+ "provider": "claude",
+ "model": "claude-v1",
+ "cost_usd": 0.008,
+ "credits_used": 8
+ },
+ "errors": [],
+ "request_id": "req_nw_en_prof_001"
+ }
+ ```
+
+
+
+ ```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": "friendly",
+ "context": {
+ "platform": "youtube",
+ "brand_voice": "Fun and energetic cooking channel"
+ }
+ }'
+ ```
+
+
diff --git a/api-reference/detect.mdx b/api-reference/detect.mdx
index 2169b2c..2baf45f 100644
--- a/api-reference/detect.mdx
+++ b/api-reference/detect.mdx
@@ -83,6 +83,8 @@ result = nawa.detect(text="وش رايكم بالمحتوى الجديد؟")
| Field | Type | Description |
|-------|------|-------------|
+| `id` | string | Unique detection ID (format: `det_nw_xxx`) |
+| `object` | string | Always `"detection"` |
| `text` | string | The original input text |
| `language` | string | Detected language: `ar`, `en`, or `mixed` |
| `dialect` | string or null | Detected Arabic dialect: `gulf`, `egyptian`, `levantine`, `msa`. Null if not Arabic. |
diff --git a/api-reference/feedback.mdx b/api-reference/feedback.mdx
index 4cddf8b..e245645 100644
--- a/api-reference/feedback.mdx
+++ b/api-reference/feedback.mdx
@@ -17,14 +17,22 @@ Submit reinforcement learning from human feedback (RLHF) to continuously improve
## Request
+### Headers
+
+| Header | Required | Description |
+|--------|----------|-------------|
+| `Authorization` | Yes | `Bearer nawa_live_sk_xxx` or `Bearer nawa_test_sk_xxx` |
+| `Content-Type` | Yes | `application/json` |
+
### Body parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
-| `request_id` | string | Yes | The `request_id` from the original classification response. |
-| `field` | string | Yes | The field to correct: `intent`, `sentiment`, `dialect`, `toxicity`, `category`. |
-| `expected_value` | string | Yes | The correct value the model should have returned. |
-| `comment` | string | No | Optional free-text explanation of why this correction is needed. |
+| `classification_id` | string | Yes | The classification ID (format: `cls_nw_xxx`) from the original classify response. |
+| `rating` | string | Yes | Your assessment: `correct`, `incorrect`, or `partial`. |
+| `corrected_intent` | string[] | No | The correct intent(s) the model should have returned. |
+| `corrected_sentiment` | string | No | The correct sentiment: `positive`, `negative`, `neutral`, or `mixed`. |
+| `comment` | string | No | Free-text explanation of why this correction is needed. |
### Example request
@@ -32,30 +40,41 @@ Submit reinforcement learning from human feedback (RLHF) to continuously improve
```bash cURL
curl -X POST https://api.trynawa.com/v1/feedback \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
- "request_id": "req_abc123def456",
- "field": "dialect",
- "expected_value": "levantine",
+ "classification_id": "cls_nw_abc123def456",
+ "rating": "incorrect",
+ "corrected_intent": ["question"],
+ "corrected_sentiment": "neutral",
"comment": "This is Lebanese Arabic, not Gulf"
}'
```
```typescript TypeScript
+import { Nawa } from '@nawalabs/sdk'
+
+const nawa = new Nawa({ apiKey: process.env.NAWA_API_KEY })
+
const { data, error } = await nawa.feedback.submit({
- requestId: 'req_abc123def456',
- field: 'dialect',
- expectedValue: 'levantine',
+ classificationId: 'cls_nw_abc123def456',
+ rating: 'incorrect',
+ correctedIntent: ['question'],
+ correctedSentiment: 'neutral',
comment: 'This is Lebanese Arabic, not Gulf'
})
```
```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="your_api_key")
+
result = nawa.feedback.submit(
- request_id="req_abc123def456",
- field="dialect",
- expected_value="levantine",
+ classification_id="cls_nw_abc123def456",
+ rating="incorrect",
+ corrected_intent=["question"],
+ corrected_sentiment="neutral",
comment="This is Lebanese Arabic, not Gulf"
)
```
@@ -70,11 +89,32 @@ result = nawa.feedback.submit(
{
"success": true,
"result": {
- "feedback_id": "fb_xyz789",
- "status": "accepted",
- "message": "Thank you! Your feedback helps improve NAWA's accuracy."
+ "id": "fb_nw_xyz789",
+ "object": "feedback",
+ "classification_id": "cls_nw_abc123def456",
+ "rating": "incorrect",
+ "acknowledged": true
},
"errors": [],
- "request_id": "req_fb_abc123"
+ "request_id": "req_nw_fb_abc123"
}
```
+
+### Result fields
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `id` | string | Unique feedback ID (format: `fb_nw_xxx`) |
+| `object` | string | Always `"feedback"` |
+| `classification_id` | string | The classification this feedback applies to |
+| `rating` | string | The rating you submitted |
+| `acknowledged` | boolean | Always `true` on success |
+
+### Error responses
+
+| Status | Type | When |
+|--------|------|------|
+| 400 | `invalid_request_error` | Missing `classification_id` or `rating`, invalid rating value |
+| 401 | `authentication_error` | Invalid or missing API key |
+| 404 | `not_found_error` | Classification ID does not exist |
+| 500 | `api_error` | Internal error |
diff --git a/api-reference/health.mdx b/api-reference/health.mdx
index ca110e8..1d6b46f 100644
--- a/api-reference/health.mdx
+++ b/api-reference/health.mdx
@@ -5,14 +5,41 @@ description: "Check the operational status of the NAWA API and its dependencies.
api: "GET https://api.trynawa.com/v1/health"
---
-Check the operational status of the NAWA API. This endpoint is **free** and does **not** require authentication.
+Check the operational status of the NAWA API and its backing services. This endpoint is **free** and does **not** require authentication.
## Request
-```bash
+
+
+```bash cURL
curl https://api.trynawa.com/v1/health
```
+```typescript TypeScript
+const response = await fetch('https://api.trynawa.com/v1/health')
+const data = await response.json()
+
+if (data.result.status === 'healthy') {
+ console.log('All systems operational')
+} else {
+ console.log('Degraded:', data.result.services)
+}
+```
+
+```python Python
+import requests
+
+response = requests.get("https://api.trynawa.com/v1/health")
+data = response.json()
+
+if data["result"]["status"] == "healthy":
+ print("All systems operational")
+else:
+ print("Degraded:", data["result"]["services"])
+```
+
+
+
## Response
### Healthy response (200)
@@ -22,41 +49,71 @@ curl https://api.trynawa.com/v1/health
"success": true,
"result": {
"status": "healthy",
- "version": "1.0.0",
+ "version": "v1",
"services": {
- "api": "operational",
- "classification": "operational",
- "database": "operational",
- "cache": "operational"
+ "database": {
+ "status": "operational",
+ "latency_ms": 12
+ },
+ "redis": {
+ "status": "operational",
+ "latency_ms": 3
+ },
+ "nagl": {
+ "status": "operational"
+ }
},
- "timestamp": "2025-01-15T12:00:00Z"
+ "timestamp": "2025-01-15T12:00:00Z",
+ "latency_ms": 15
},
"errors": [],
- "request_id": "req_hlt_abc123"
+ "request_id": "req_nw_hlt_abc123"
}
```
-### Degraded response (200)
+### Degraded response (503)
+
+When one or more services are unhealthy, the endpoint returns a 503 status:
```json
{
"success": true,
"result": {
"status": "degraded",
- "version": "1.0.0",
+ "version": "v1",
"services": {
- "api": "operational",
- "classification": "degraded",
- "database": "operational",
- "cache": "operational"
+ "database": {
+ "status": "operational",
+ "latency_ms": 12
+ },
+ "redis": {
+ "status": "degraded",
+ "latency_ms": 450
+ },
+ "nagl": {
+ "status": "operational"
+ }
},
- "timestamp": "2025-01-15T12:00:00Z"
+ "timestamp": "2025-01-15T12:00:00Z",
+ "latency_ms": 462
},
"errors": [],
- "request_id": "req_hlt_def456"
+ "request_id": "req_nw_hlt_def456"
}
```
+### Result fields
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `status` | string | Overall status: `healthy` or `degraded` |
+| `version` | string | API version (`v1`) |
+| `services.database` | object | Database status and latency |
+| `services.redis` | object | Redis cache status and latency |
+| `services.nagl` | object | NAGL engine status |
+| `timestamp` | string | ISO 8601 timestamp of the check |
+| `latency_ms` | integer | Total health check latency in milliseconds |
+
For real-time status monitoring, visit [status.trynawa.com](https://status.trynawa.com).
diff --git a/api-reference/moderate.mdx b/api-reference/moderate.mdx
index 947d30e..abbde7c 100644
--- a/api-reference/moderate.mdx
+++ b/api-reference/moderate.mdx
@@ -184,6 +184,8 @@ When content is flagged, the response includes specific flags, severity scores,
| Field | Type | Description |
|-------|------|-------------|
+| `id` | string | Unique moderation ID (format: `mod_nw_xxx`) |
+| `object` | string | Always `"moderation"` |
| `text` | string | The original input text |
| `is_safe` | boolean | Whether the content passed moderation |
| `verdict` | string | `safe` or `flagged` |
diff --git a/api-reference/rubric-classify.mdx b/api-reference/rubric-classify.mdx
index 4489175..d17c026 100644
--- a/api-reference/rubric-classify.mdx
+++ b/api-reference/rubric-classify.mdx
@@ -1,11 +1,11 @@
---
title: "Rubric Classify"
sidebarTitle: "POST /v1/rubric/classify"
-description: "Classify a comment against a custom rubric with predefined scoring criteria."
+description: "Classify text against a custom rubric with user-defined categories and confidence thresholds."
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 descriptions, enable multi-label classification, and set confidence thresholds for domain-specific workflows.
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`).
@@ -13,15 +13,28 @@ Classify a comment against a custom rubric. Define your own categories and scori
## 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`, or `allam`. |
+
### 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. |
+| `text` | string | Yes | The text to classify. Min 1 character. |
+| `rubric` | object | Yes | The rubric definition. |
+| `rubric.categories` | array | Yes | Array of category objects. Each object has a `name` (string, required) and optional `description` (string). 1--20 categories allowed. |
+| `rubric.multi_label` | boolean | No | Allow multiple category matches. Default: `false`. |
+| `rubric.confidence_threshold` | number | No | Minimum confidence score to include a category (0.0--1.0). Default: `0.5`. |
### Example request
@@ -29,52 +42,60 @@ Classify a comment against a custom rubric. Define your own categories and scori
```bash cURL
curl -X POST https://api.trynawa.com/v1/rubric/classify \
- -H "Authorization: Bearer nawa_test_sk_xxx" \
+ -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"
+ "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
+ }
}'
```
```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: ['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' }
+ ],
+ multiLabel: false,
+ confidenceThreshold: 0.5
+ }
})
```
```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="your_api_key")
+
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",
)
```
@@ -88,23 +109,24 @@ 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_pon1yom9bkfe",
+ "object": "rubric_classification",
+ "categories": [
+ { "name": "translation_request", "confidence": 0.94 },
+ { "name": "technical_issue", "confidence": 0.03 },
+ { "name": "content_feedback", "confidence": 0.02 },
+ { "name": "off_topic", "confidence": 0.01 }
+ ],
+ "multi_label": false,
"language": "ar",
- "model": "nagl-v1",
- "cached": false
+ "provider": "allam",
+ "model": "allam-v1",
+ "fallback_used": false,
+ "cost_usd": 0.003,
+ "credits_used": 3
},
"errors": [],
- "request_id": "req_rub123abc456"
+ "request_id": "req_nw_rub123abc456"
}
```
@@ -112,10 +134,27 @@ result = nawa.rubric.classify(
| 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 | Unique rubric classification ID (format: `rcl_nw_xxx`) |
+| `object` | string | Always `"rubric_classification"` |
+| `categories` | array | Array of category results, each with `name` (string) and `confidence` (number, 0--1). Sorted by confidence descending. |
+| `multi_label` | boolean | Whether multi-label classification was used |
+| `language` | string | Detected language: `ar`, `en`, or `mixed` |
+| `provider` | string | AI provider used: `claude`, `gemini`, or `allam` |
+| `model` | string | Specific model version used |
+| `fallback_used` | boolean | Whether a fallback provider was used |
+| `cost_usd` | number | Cost of this request in USD |
+| `credits_used` | integer | Credits deducted from your balance |
+
+### Error responses
+
+| Status | Type | When |
+|--------|------|------|
+| 400 | `invalid_request_error` | Missing `text`, missing or invalid `rubric`, too many categories (max 20) |
+| 401 | `authentication_error` | Invalid or missing API key |
+| 402 | `insufficient_credits` | No credits remaining |
+| 429 | `rate_limit_error` | Rate limit exceeded |
+| 500 | `api_error` | Internal or provider error |
+
+
+ Use `multi_label: true` when comments may match more than one category. For example, "The audio is bad and where are the subtitles?" could match both `technical_issue` and `translation_request`.
+
diff --git a/api-reference/translate.mdx b/api-reference/translate.mdx
index c10d2ba..8a1e883 100644
--- a/api-reference/translate.mdx
+++ b/api-reference/translate.mdx
@@ -107,6 +107,8 @@ Translate text between English and Arabic with dialect awareness. Generates cult
| Field | Type | Description |
|-------|------|-------------|
+| `id` | string | Unique translation ID (format: `trn_nw_xxx`) |
+| `object` | string | Always `"translation"` |
| `text` | string | The original input text |
| `translated_text` | string | The translated output |
| `source_language` | string | Detected or specified source language |
diff --git a/api-reference/usage.mdx b/api-reference/usage.mdx
index d4b1b6b..c7e462c 100644
--- a/api-reference/usage.mdx
+++ b/api-reference/usage.mdx
@@ -9,21 +9,61 @@ Retrieve your API usage statistics including request counts, credit consumption,
## Request
+### Headers
+
+| Header | Required | Description |
+|--------|----------|-------------|
+| `Authorization` | Yes | `Bearer nawa_live_sk_xxx` or `Bearer nawa_test_sk_xxx` |
+
### Query parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `from` | string | No | Start date (ISO 8601). Default: start of current month. |
| `to` | string | No | End date (ISO 8601). Default: now. |
-| `group_by` | string | No | Group by: `day`, `week`, `month`, `endpoint`. Default: `day`. |
+| `group_by` | string | No | Group results by: `endpoint` or `day`. Default: `endpoint`. |
### Example request
-```bash
+
+
+```bash cURL
curl "https://api.trynawa.com/v1/usage?from=2025-01-01T00:00:00Z&group_by=endpoint" \
- -H "Authorization: Bearer nawa_test_sk_xxx"
+ -H "Authorization: Bearer nawa_live_sk_xxx"
+```
+
+```typescript TypeScript
+import { Nawa } from '@nawalabs/sdk'
+
+const nawa = new Nawa({ apiKey: process.env.NAWA_API_KEY })
+
+const { data, error } = await nawa.usage({
+ from: '2025-01-01T00:00:00Z',
+ groupBy: 'endpoint'
+})
+
+if (data) {
+ console.log(`Total requests: ${data.usage.total_requests}`)
+ console.log(`Cache hit rate: ${data.usage.cache_hit_rate}`)
+}
```
+```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="your_api_key")
+
+result = nawa.usage(
+ from_date="2025-01-01T00:00:00Z",
+ group_by="endpoint"
+)
+
+print(f"Total requests: {result.usage.total_requests}")
+print(f"Cache hit rate: {result.usage.cache_hit_rate}")
+```
+
+
+
## Response
### Success response (200)
@@ -32,44 +72,39 @@ curl "https://api.trynawa.com/v1/usage?from=2025-01-01T00:00:00Z&group_by=endpoi
{
"success": true,
"result": {
- "period": {
- "from": "2025-01-01T00:00:00Z",
- "to": "2025-01-31T23:59:59Z"
+ "usage": {
+ "total_requests": 12450,
+ "total_cost": 68.70,
+ "cache_hits": 2835,
+ "cache_hit_rate": 0.23,
+ "period": {
+ "from": "2025-01-01T00:00:00Z",
+ "to": "2025-01-31T23:59:59Z"
+ }
},
- "total_requests": 12450,
- "total_cost": 68.70,
- "cache_hit_rate": 0.23,
"by_endpoint": [
{
"endpoint": "/v1/classify",
"requests": 8500,
"cost": 51.00,
- "cache_hits": 1955,
- "avg_latency_ms": 820
+ "cache_hits": 1955
},
{
"endpoint": "/v1/rubric/classify",
"requests": 2200,
"cost": 6.60,
- "cache_hits": 880,
- "avg_latency_ms": 650
+ "cache_hits": 880
},
{
- "endpoint": "/v1/comments/:id/reply",
+ "endpoint": "/v1/comments/reply",
"requests": 1750,
"cost": 14.00,
- "cache_hits": 0,
- "avg_latency_ms": 1200
+ "cache_hits": 0
}
- ],
- "balance": {
- "current": 31.30,
- "credits_purchased": 100.00,
- "credits_used": 68.70
- }
+ ]
},
"errors": [],
- "request_id": "req_usg_abc123"
+ "request_id": "req_nw_usg_abc123"
}
```
@@ -77,8 +112,18 @@ curl "https://api.trynawa.com/v1/usage?from=2025-01-01T00:00:00Z&group_by=endpoi
| Field | Type | Description |
|-------|------|-------------|
-| `total_requests` | integer | Total API requests in the period |
-| `total_cost` | number | Total credit cost in USD |
-| `cache_hit_rate` | number | Percentage of requests served from cache (0–1) |
-| `by_endpoint` | array | Breakdown by endpoint |
-| `balance` | object | Current balance and credit history |
+| `usage.total_requests` | integer | Total API requests in the period |
+| `usage.total_cost` | number | Total credit cost in USD |
+| `usage.cache_hits` | integer | Number of requests served from cache |
+| `usage.cache_hit_rate` | number | Fraction of requests served from cache (0--1) |
+| `usage.period.from` | string or null | Start of the usage period |
+| `usage.period.to` | string or null | End of the usage period |
+| `by_endpoint` | array | Breakdown by endpoint (when `group_by=endpoint`) |
+| `by_day` | array | Breakdown by date (when `group_by=day`) |
+
+### Error responses
+
+| Status | Type | When |
+|--------|------|------|
+| 401 | `authentication_error` | Invalid or missing API key |
+| 500 | `api_error` | Internal error |
diff --git a/api-reference/webhooks-manage.mdx b/api-reference/webhooks-manage.mdx
new file mode 100644
index 0000000..7831b09
--- /dev/null
+++ b/api-reference/webhooks-manage.mdx
@@ -0,0 +1,192 @@
+---
+title: "Manage Webhooks"
+sidebarTitle: "Webhooks"
+description: "Create, list, and delete webhook endpoints for real-time event notifications."
+---
+
+Manage your webhook endpoints to receive real-time notifications when events occur in your NAWA account. See the [webhooks overview](/webhooks) for event types, payload format, and signature verification.
+
+## Create a webhook
+
+**POST** `https://api.trynawa.com/v1/webhooks`
+
+Register a new webhook endpoint to receive event notifications.
+
+### Body parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `url` | string | Yes | The HTTPS URL to receive webhook events. Must use HTTPS. |
+| `events` | string[] | Yes | Event types to subscribe to. |
+
+**Supported events:** `classification.completed`, `classification.failed`, `credits.low`, `credits.exhausted`
+
+### Example request
+
+
+
+```bash cURL
+curl -X POST https://api.trynawa.com/v1/webhooks \
+ -H "Authorization: Bearer nawa_live_sk_xxx" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "url": "https://example.com/webhooks/nawa",
+ "events": ["classification.completed", "credits.low"]
+ }'
+```
+
+```typescript TypeScript
+import { Nawa } from '@nawalabs/sdk'
+
+const nawa = new Nawa({ apiKey: process.env.NAWA_API_KEY })
+
+const { data, error } = await nawa.webhooks.create({
+ url: 'https://example.com/webhooks/nawa',
+ events: ['classification.completed', 'credits.low']
+})
+
+// Store the signing secret securely -- it is shown only once
+console.log(data.signing_secret)
+```
+
+```python Python
+from nawa import Nawa
+
+nawa = Nawa(api_key="your_api_key")
+
+result = nawa.webhooks.create(
+ url="https://example.com/webhooks/nawa",
+ events=["classification.completed", "credits.low"]
+)
+
+# Store the signing secret securely -- it is shown only once
+print(result.signing_secret)
+```
+
+
+
+### Success response (201)
+
+```json
+{
+ "success": true,
+ "result": {
+ "id": "wh_abc123",
+ "url": "https://example.com/webhooks/nawa",
+ "events": ["classification.completed", "credits.low"],
+ "signing_secret": "nawa_wh_sk_abc123def456",
+ "active": true,
+ "created_at": "2025-01-15T12:00:00Z"
+ },
+ "errors": [],
+ "request_id": "req_nw_wh_abc123"
+}
+```
+
+
+ The `signing_secret` is shown only once at creation time. Store it securely. You will need it to [verify webhook signatures](/webhooks#signature-verification).
+
+
+---
+
+## List webhooks
+
+**GET** `https://api.trynawa.com/v1/webhooks`
+
+Retrieve all registered webhook endpoints for your account.
+
+### Example request
+
+
+
+```bash cURL
+curl https://api.trynawa.com/v1/webhooks \
+ -H "Authorization: Bearer nawa_live_sk_xxx"
+```
+
+```typescript TypeScript
+const { data, error } = await nawa.webhooks.list()
+```
+
+```python Python
+result = nawa.webhooks.list()
+```
+
+
+
+### Success response (200)
+
+```json
+{
+ "success": true,
+ "result": {
+ "webhooks": [
+ {
+ "id": "wh_abc123",
+ "url": "https://example.com/webhooks/nawa",
+ "events": ["classification.completed", "credits.low"],
+ "active": true,
+ "created_at": "2025-01-15T12:00:00Z"
+ }
+ ]
+ },
+ "errors": [],
+ "request_id": "req_nw_wh_list_001"
+}
+```
+
+---
+
+## Delete a webhook
+
+**DELETE** `https://api.trynawa.com/v1/webhooks?id={webhook_id}`
+
+Deactivate and remove a webhook endpoint.
+
+### Query parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `id` | string | Yes | The webhook ID to delete. |
+
+### Example request
+
+
+
+```bash cURL
+curl -X DELETE "https://api.trynawa.com/v1/webhooks?id=wh_abc123" \
+ -H "Authorization: Bearer nawa_live_sk_xxx"
+```
+
+```typescript TypeScript
+const { data, error } = await nawa.webhooks.delete('wh_abc123')
+```
+
+```python Python
+result = nawa.webhooks.delete("wh_abc123")
+```
+
+
+
+### Success response (200)
+
+```json
+{
+ "success": true,
+ "result": {
+ "id": "wh_abc123",
+ "deleted": true
+ },
+ "errors": [],
+ "request_id": "req_nw_wh_del_001"
+}
+```
+
+### Error responses (all operations)
+
+| Status | Type | When |
+|--------|------|------|
+| 400 | `invalid_request_error` | Missing `url` or `events`, invalid URL (not HTTPS), invalid event type |
+| 401 | `authentication_error` | Invalid or missing API key |
+| 404 | `not_found_error` | Webhook ID does not exist |
+| 500 | `api_error` | Internal error |
diff --git a/docs.json b/docs.json
index 8f8f901..9ec6df8 100644
--- a/docs.json
+++ b/docs.json
@@ -62,7 +62,8 @@
"api-reference/comments-list",
"api-reference/analytics",
"api-reference/health",
- "api-reference/usage"
+ "api-reference/usage",
+ "api-reference/webhooks-manage"
]
}
]