whatsapp fixes

This commit is contained in:
debu-2 2026-10-03 00:54:52 +05:30
parent ff01efe4bb
commit 248acba741
5 changed files with 425 additions and 38 deletions

View file

@ -24,6 +24,7 @@ class SendAgentMessagePayload(BaseModel):
customer_name: str = Field(min_length=1, max_length=120)
report_group: str = Field(min_length=3, max_length=50)
report_id: str | None = Field(default=None, max_length=120)
report_url: str | None = Field(default=None, max_length=500)
def serialize_agent_template(template: AgentMessageTemplate, *, subscribed: bool = False) -> dict:
@ -97,31 +98,46 @@ def _validate_report_id(report_id: str) -> str:
return cleaned
def _build_report_url(
template: AgentMessageTemplate,
report_group: str,
report_id: str,
override: str | None = None,
) -> str:
if override:
return override.strip()
base = (template.button_url_base or "https://urmiai.com/reports/").rstrip("/")
return f"{base}/{report_group}/{report_id}"
def _build_template_components(
template: AgentMessageTemplate,
customer_name: str,
report_group: str,
report_id: str,
report_url: str,
) -> list[dict]:
"""Build Meta template components using positional variables.
agent_run_completion uses:
body {{1}} -> customer name
button {{1}} -> report URL path suffix OR full URL depending on Meta template config.
We pass the full hosted report URL for the button so the View Report link resolves correctly.
"""
components: list[dict] = [
{
"type": "body",
"parameters": [
{
"type": "text",
"parameter_name": "customer_name",
"text": customer_name.strip(),
}
],
"parameters": [{"type": "text", "text": customer_name.strip()}],
}
]
if template.button_label and template.button_url_base:
# Meta URL button: pass path suffix relative to button_url_base (e.g. desi-clans-test/2026-10-03)
base = template.button_url_base.rstrip("/")
button_param = report_url[len(base) + 1 :] if report_url.startswith(f"{base}/") else report_url
components.append(
{
"type": "button",
"sub_type": "url",
"index": "0",
"parameters": [{"type": "text", "text": f"{report_group}/{report_id}"}],
"parameters": [{"type": "text", "text": button_param}],
}
)
return components
@ -148,7 +164,8 @@ async def send_agent_template_message(
report_group = _validate_report_group(payload.report_group)
report_id = _validate_report_id(payload.report_id or f"run-{secrets.token_hex(3)}")
components = _build_template_components(template, payload.customer_name, report_group, report_id)
report_url = _build_report_url(template, report_group, report_id, payload.report_url)
components = _build_template_components(template, payload.customer_name, report_url)
client = _whatsapp_client(db)
try:
@ -170,6 +187,7 @@ async def send_agent_template_message(
"customer_name": payload.customer_name.strip(),
"report_group": report_group,
"report_id": report_id,
"report_url": report_url,
},
wa_message_id=wa_message_id,
status="sent",
@ -179,11 +197,6 @@ async def send_agent_template_message(
db.commit()
db.refresh(log)
report_url = (
f"{template.button_url_base.rstrip('/')}/{report_group}/{report_id}"
if template.button_url_base
else None
)
return {
"success": True,
"template": template.slug,
@ -279,22 +292,24 @@ def build_agent_message_docs(template: AgentMessageTemplate) -> dict:
"customer_name": "Recipient name inserted into the template body",
"report_group": "Urmiport report group slug used in the hosted report URL",
"report_id": "Optional report postfix; auto-generated when omitted",
"report_url": "Optional full report URL override for the WhatsApp button (auto-built when omitted)",
},
"example": {
"template": template.slug,
"to": "919149154337",
"customer_name": "Suyash",
"report_group": "acme-agent-runs",
"report_id": "run-abc123",
"report_group": "desi-clans-test",
"report_id": "2026-10-03",
"report_url": "https://urmiai.com/reports/desi-clans-test/2026-10-03",
},
"response_example": {
"success": True,
"template": template.slug,
"to": "919149154337",
"customer_name": "Suyash",
"report_group": "acme-agent-runs",
"report_id": "run-abc123",
"report_url": f"{template.button_url_base or ''}acme-agent-runs/run-abc123",
"report_group": "desi-clans-test",
"report_id": "2026-10-03",
"report_url": "https://urmiai.com/reports/desi-clans-test/2026-10-03",
"wa_message_id": "wamid.HBg...",
"dispatch_id": "00000000-0000-0000-0000-000000000001",
},
@ -304,5 +319,6 @@ def build_agent_message_docs(template: AgentMessageTemplate) -> dict:
"Messages are sent from the Urmi AI WhatsApp business number on your behalf.",
"Create the report group in Console → Agent → Urmiport before sending.",
"If report_id is omitted, Urmi generates a unique postfix automatically.",
"The WhatsApp button uses positional template variables: body {{1}} = customer_name, button suffix = report_group/report_id.",
],
}

View file

@ -22,25 +22,18 @@ DEFAULT_AGENT_TEMPLATES = [
"category": "utility",
"parameters": [
{
"name": "customer_name",
"name": "{{1}}",
"type": "string",
"required": True,
"description": "Recipient display name shown in the greeting",
"description": "Positional body variable — recipient display name",
"example": "Suyash",
},
{
"name": "report_group",
"name": "{{2}}",
"type": "string",
"required": True,
"description": "Urmiport report group slug used in the hosted report URL",
"example": "acme-agent-runs",
},
{
"name": "report_id",
"type": "string",
"required": True,
"description": "Report postfix appended after the report group in the View Report button URL",
"example": "run-abc123",
"description": "Positional button variable — report path suffix (report_group/report_id)",
"example": "desi-clans-test/2026-10-03",
},
],
"button_label": "View Report",

View file

@ -55,7 +55,13 @@ def _explorer_doc_for_template(template: AgentMessageTemplate) -> dict:
"type": "string",
"required": False,
"description": "Report postfix; auto-generated when omitted",
"example": "run-abc123",
"example": "2026-10-03",
},
"report_url": {
"type": "string",
"required": False,
"description": "Full hosted report URL for the WhatsApp button; auto-built when omitted",
"example": "https://urmiai.com/reports/desi-clans-test/2026-10-03",
},
},
"responses": {
@ -66,9 +72,9 @@ def _explorer_doc_for_template(template: AgentMessageTemplate) -> dict:
"template": template.slug,
"to": "919149154337",
"customer_name": "Suyash",
"report_group": "acme-agent-runs",
"report_id": "run-abc123",
"report_url": f"{template.button_url_base or ''}acme-agent-runs/run-abc123",
"report_group": "desi-clans-test",
"report_id": "2026-10-03",
"report_url": "https://urmiai.com/reports/desi-clans-test/2026-10-03",
"wa_message_id": "wamid.HBg...",
"dispatch_id": "00000000-0000-0000-0000-000000000001",
},

View file

@ -0,0 +1,365 @@
# Urmiport & Agent WhatsApp APIs
This document describes the two APIs used together to **host an HTML report** and **notify a user on WhatsApp** with a link to that report.
| API | Purpose |
|-----|---------|
| **Urmiport — Publish report** | Create or update a hosted HTML report |
| **Agent messages — Send WhatsApp** | Send an approved WhatsApp template with a dynamic View Report button |
**Base URL:** `https://urmiai.com`
**Authentication:** Urmi API key in every request
```http
Authorization: Bearer urmi_live_<your_api_key>
```
Alternate header: `X-Api-Key: urmi_live_<your_api_key>`
Create API keys in the Urmi console: **Develop → API Keys**.
---
## End-to-end flow
```text
1. Console → Agent → Urmiport
Create a report group (e.g. desi-clans-test)
2. Console → Agent → UrmiAI
Subscribe to the agent_run_completion template
3. POST /api/v1/urmiport/reports
Publish HTML for report_group + report_id
4. POST /api/v1/agent/messages/send
Send WhatsApp message; button links to the hosted report
5. User opens
https://urmiai.com/reports/{report_group}/{report_id}
```
Typical order: **publish the report first**, then **send the WhatsApp message** so the link is live when the user taps View Report.
---
## Prerequisites (console setup)
### 1. Create a report group
**Console → Agent → Urmiport → New report group**
| Setting | Description |
|---------|-------------|
| **Report group** | URL slug, 3–50 chars, lowercase letters, numbers, hyphens (e.g. `desi-clans-test`) |
| **Default access** | `public` or `password` |
| **Report ID mode** | `auto` — Urmi generates `report_id` when omitted; `manual` — you must send `report_id` in the API |
Hosted URL pattern:
```text
https://urmiai.com/reports/{report_group}/{report_id}
```
### 2. Subscribe to the WhatsApp template
**Console → Agent → UrmiAI**
Subscribe to **`agent_run_completion`** (display name: *Agent Run Success*).
Messages are sent from the Urmi AI WhatsApp Business number on your behalf.
---
## API 1 — Publish Urmiport HTML report
Create or update a hosted HTML report. The public page renders **only your HTML** — no Urmi branding or chrome.
### Endpoint
```http
POST /api/v1/urmiport/reports
Content-Type: application/json
Authorization: Bearer urmi_live_<your_api_key>
```
### Request body
| Field | Required | Type | Description |
|-------|----------|------|-------------|
| `report_group` | Yes | string | Report group slug created in Urmiport (e.g. `desi-clans-test`) |
| `body` | Yes | string | Full HTML document or fragment (email-style HTML is supported) |
| `report_id` | Conditional | string | Report postfix. **Required** when the group uses manual ID mode; optional for auto groups |
| `access` | No | string | `public` (default) or `password` |
| `password` | Conditional | string | Required when `access` is `password`, unless the group already has a default password |
### Validation rules
- **report_group:** 3–50 chars, lowercase `a-z`, `0-9`, hyphens; must already exist in your account
- **report_id:** letters, numbers, dots, underscores, hyphens; max 120 chars
- **Upsert:** same `report_group` + `report_id` updates the existing HTML body
### Example — public report (manual report ID)
```bash
curl -X POST 'https://urmiai.com/api/v1/urmiport/reports' \
-H 'Authorization: Bearer urmi_live_<your_api_key>' \
-H 'Content-Type: application/json' \
-d '{
"report_group": "desi-clans-test",
"report_id": "desi-clans-demo-v1",
"access": "public",
"body": "<html><body><h1>Agent run complete</h1><p>All checks passed.</p></body></html>"
}'
```
### Example — password-protected report
```bash
curl -X POST 'https://urmiai.com/api/v1/urmiport/reports' \
-H 'Authorization: Bearer urmi_live_<your_api_key>' \
-H 'Content-Type: application/json' \
-d '{
"report_group": "desi-clans-test",
"report_id": "run-confidential-001",
"access": "password",
"password": "my-secret-pass",
"body": "<html><body><h1>Confidential report</h1></body></html>"
}'
```
### Example — auto-generated report ID
When the report group uses **auto** ID mode, omit `report_id`:
```bash
curl -X POST 'https://urmiai.com/api/v1/urmiport/reports' \
-H 'Authorization: Bearer urmi_live_<your_api_key>' \
-H 'Content-Type: application/json' \
-d '{
"report_group": "acme-agent-runs",
"access": "public",
"body": "<html><body><h1>Run complete</h1></body></html>"
}'
```
Urmi returns a generated `report_id` such as `run-a1b2c3`.
### Success response `200 OK`
```json
{
"success": true,
"id": "11926afa-c648-48f2-909e-67434f878232",
"report_group": "desi-clans-test",
"report_id": "desi-clans-demo-v1",
"access": "public",
"password_protected": false,
"url": "https://urmiai.com/reports/desi-clans-test/desi-clans-demo-v1",
"created_at": "2026-10-02T17:13:32.468390Z",
"updated_at": "2026-10-02T17:13:32.468390Z"
}
```
### Error responses
| Status | Meaning |
|--------|---------|
| `401` | Missing or invalid API key |
| `404` | Report group not found — create it in Console → Agent → Urmiport |
| `422` | Validation error (invalid slug, missing `report_id` for manual groups, missing password, etc.) |
### Public viewing
| Access | Behaviour |
|--------|-----------|
| **Public** | `GET https://urmiai.com/reports/{report_group}/{report_id}` renders HTML directly |
| **Password** | User sees a password gate; after unlock, only your HTML is shown |
Internal metadata endpoint (no auth):
```http
GET /api/v1/urmiport/view/{report_group}/{report_id}
POST /api/v1/urmiport/view/{report_group}/{report_id}/unlock
```
### HTML capabilities
Reports support plain **HTML, CSS, and JavaScript** — including charts, tables, branding, and client-side animations. Complex dashboards (canvas charts, live counters, responsive layouts) are supported.
### Machine-readable docs
```http
GET /api/v1/urmiport/docs
GET /api/v1/urmiport/reports/docs
```
Also available in the console: **Agent → Urmiport** and **Develop → API Explorer**.
---
## API 2 — Send WhatsApp report notification
Send an approved agent WhatsApp template. The template includes a **View Report** button whose URL is built from `report_group` and `report_id`.
### Endpoint
```http
POST /api/v1/agent/messages/send
Content-Type: application/json
Authorization: Bearer urmi_live_<your_api_key>
```
### Request body
| Field | Required | Type | Description |
|-------|----------|------|-------------|
| `template` | Yes | string | Subscribed template slug. Use `agent_run_completion` |
| `to` | Yes | string | Recipient WhatsApp number with country code, no `+` (e.g. `919149154337`) |
| `customer_name` | Yes | string | Name inserted into the template body greeting |
| `report_group` | Yes | string | Urmiport report group slug (same as in publish API) |
| `report_id` | No | string | Report postfix. If omitted, Urmi auto-generates one (e.g. `run-a1b2c3`) |
| `report_url` | No | string | Full hosted report URL override. Auto-built as `https://urmiai.com/reports/{report_group}/{report_id}` when omitted |
### Template details — `agent_run_completion`
| Property | Value |
|----------|-------|
| **Slug** | `agent_run_completion` |
| **Meta template name** | `agent_run_completion` |
| **Header** | Agent Run Complete |
| **Body** | Hello {{1}}, your agent run is complete… |
| **Button** | View Report → `https://urmiai.com/reports/{{1}}` |
The Meta template uses **positional** variables (not named):
| Variable | Maps to API field | Example |
|----------|-------------------|---------|
| `{{1}}` (body) | `customer_name` | `Suyash` |
| `{{1}}` (button) | `report_group`/`report_id` path suffix | `desi-clans-test/2026-10-03` |
Urmi sends the button suffix `desi-clans-test/2026-10-03` so the final link is:
`https://urmiai.com/reports/desi-clans-test/2026-10-03`
> **Common bug:** If body parameters are sent as named (`parameter_name`) instead of positional, Meta leaves `{{1}}` literal in the URL, producing broken links like `https://urmiai.com/reports/%7B%7B1%7D%7Ddesi-clans-test/2026-10-03`.
### Example
```bash
curl -X POST 'https://urmiai.com/api/v1/agent/messages/send' \
-H 'Authorization: Bearer urmi_live_<your_api_key>' \
-H 'Content-Type: application/json' \
-d '{
"template": "agent_run_completion",
"to": "919149154337",
"customer_name": "Suyash",
"report_group": "desi-clans-test",
"report_id": "desi-clans-demo-v1"
}'
```
### Success response `200 OK`
```json
{
"success": true,
"template": "agent_run_completion",
"to": "919149154337",
"customer_name": "Suyash",
"report_group": "desi-clans-test",
"report_id": "2026-10-03",
"report_url": "https://urmiai.com/reports/desi-clans-test/2026-10-03",
"wa_message_id": "wamid.HBg...",
"dispatch_id": "00000000-0000-0000-0000-000000000001"
}
```
### Error responses
| Status | Meaning |
|--------|---------|
| `401` | Missing or invalid API key |
| `403` | Template not subscribed — subscribe in Console → Agent → UrmiAI |
| `422` | Invalid phone number, `report_group`, or `report_id` format |
| `502` | Meta WhatsApp API error (template mismatch, WABA issue, etc.) |
### Machine-readable docs
```http
GET /api/v1/agent/messages/docs/send
```
Per-template docs (console session required):
```http
GET /api/v1/agent-templates/agent_run_completion/docs
```
Also available in the console: **Agent → UrmiAI → API docs** and **Develop → API Explorer**.
---
## Complete integration example
Publish a report, then notify the user on WhatsApp with the same `report_group` and `report_id`.
### Step 1 — Publish report
```bash
curl -X POST 'https://urmiai.com/api/v1/urmiport/reports' \
-H 'Authorization: Bearer urmi_live_<your_api_key>' \
-H 'Content-Type: application/json' \
-d '{
"report_group": "desi-clans-test",
"report_id": "desi-clans-demo-v1",
"access": "public",
"body": "<html><head><style>body{font-family:sans-serif;background:#0b1020;color:#fff;padding:24px}</style></head><body><h1>Desi Clans — Run complete</h1><p>All systems operational.</p></body></html>"
}'
```
Report URL: `https://urmiai.com/reports/desi-clans-test/desi-clans-demo-v1`
### Step 2 — Send WhatsApp notification
```bash
curl -X POST 'https://urmiai.com/api/v1/agent/messages/send' \
-H 'Authorization: Bearer urmi_live_<your_api_key>' \
-H 'Content-Type: application/json' \
-d '{
"template": "agent_run_completion",
"to": "919149154337",
"customer_name": "Suyash",
"report_group": "desi-clans-test",
"report_id": "desi-clans-demo-v1"
}'
```
The recipient receives a WhatsApp message with a **View Report** button pointing to the hosted report.
---
## Quick reference
| Item | Value |
|------|-------|
| Base URL | `https://urmiai.com` |
| Publish report | `POST /api/v1/urmiport/reports` |
| Send WhatsApp | `POST /api/v1/agent/messages/send` |
| Report URL | `https://urmiai.com/reports/{report_group}/{report_id}` |
| Template slug | `agent_run_completion` |
| Auth header | `Authorization: Bearer urmi_live_<key>` |
---
## Console links
| Task | Location |
|------|----------|
| Create report groups | Console → Agent → Urmiport |
| Subscribe WhatsApp template | Console → Agent → UrmiAI |
| Create API keys | Console → Develop → API Keys |
| Try APIs interactively | Console → Develop → API Explorer |
urmi_live_a9d92e7be1584e24aa361cb09075794a_FWsjx04IW3Z2Enqx4Lg0EybTqCYsa0Dk

View file

@ -523,7 +523,14 @@ export const agentMessagesApi = {
docs: () => jsonRequest<AgentMessageApiDoc>('/api/v1/agent/messages/docs/send'),
send: (
apiKey: string,
payload: { template: string; to: string; customer_name: string; report_group: string; report_id?: string },
payload: {
template: string
to: string
customer_name: string
report_group: string
report_id?: string
report_url?: string
},
) =>
fetch(`${API_BASE_URL}/api/v1/agent/messages/send`, {
method: 'POST',