Feedback Mobile API Reference
Integration reference for mobile feedback endpoints.
Feedback Mobile API Reference
Audience: Mobile/frontend developers Scope: Mobile feedback contracts currently implemented.
Mobile APIs
Submit Feedback
Endpoint
POST /api/mobile/feedbackAuth
Authorization: Bearer <user-jwt>
Request body
{
"category": "feature_request",
"subject": "Please add dark mode",
"message": "Dark mode would make the app easier to use at night."
}Feedback categories:
bug_reportfeature_requestgeneral_feedback
Important behavior:
- feedback is one-way in v1
- mobile users do not have list/detail endpoints for previous feedback submissions
Submit Feedback — Public (Guest)
Endpoint
POST /api/mobile/feedback/publicAuth
@Public()— none. This is a separate route fromPOST /api/mobile/feedback, not the same route with auth relaxed, because the two take different bodies. Letting a signed-in customer post the guest body would let them attribute a message to somebody else's name/email.
Rate limit
PUBLIC_CONTACT_GUEST— 5 requests / hour, keyed onip+device(apps/api/src/common/guards/ip-throttler.config.ts). Rejected requests still consume quota — the throttle guard runs before DTO validation.
Request body
{
"name": "Sita Sharma",
"email": "sita@example.com",
"phone": "+977 98XXXXXXXX",
"category": "general_feedback",
"subject": "Question about warranty",
"message": "Is the Marshall Acton III covered by a local warranty?",
"companyWebsite": ""
}| Field | Required | Notes |
|---|---|---|
name | Yes | 1-120 chars, trimmed |
email | Yes | max 255, @IsEmail() |
phone | No | max 40 |
category | Yes | bug_report | feature_request | general_feedback |
subject | Yes | 1-255 chars — the authenticated endpoint's DTO does not require this field, the guest one does |
message | Yes | 1-5000 chars |
companyWebsite | No | honeypot. Render hidden, leave empty, never autofill. forbidNonWhitelisted: true means any other undeclared field 400s. |
Response — always identical, regardless of outcome
{ "message": "Message received. We will get back to you shortly.", "data": { "status": "received" } }The response carries no id and no echo of the sender. It is the same whether the message was stored, or discarded because the honeypot was filled — so a bot learns nothing from the response, and the endpoint cannot be used to test whether an email address belongs to an existing account.
Honeypot behavior: a non-empty companyWebsite causes the submission to be logged at warn and
not persisted — no row is written to feedback_submissions — but the caller still receives the
normal 200 acknowledgement above.
Both routes notify the shop. An accepted submission writes a feedback.submitted outbox row in
the same transaction as the insert, targeting NOTIFICATIONS / notification.send_email. It
does two jobs from one row: an internal notice reaches the shop's own inbox, and the dispatcher's
relay raises a live admin notification (Feedback_READ) — the feed is a side-effect of dispatch, so
an event with no job to dispatch cannot reach the stream.
The destination is fixed configuration — SUPPORT_EMAIL — never the address in the request.
That is what makes it safe on an unauthenticated route. An acknowledgement posted back to whatever
address a form carried would turn this endpoint into an outbound-email amplifier: anyone could make
the API mail a third party by typing their address into the contact form.
The honeypot path is upstream of all of it. A discarded submission opens no transaction, writes no row and queues nothing, so a bot filling every field cannot make the endpoint send anything at all.
Errors
| HTTP | Condition |
|---|---|
400 | validation failure — missing/invalid email, blank message, or an undeclared field |
429 | over 5 requests/hour for this IP+device pair |
Not to be confused with POST /api/mobile/feedback above — that route still requires a bearer token
and takes a different body (no name/email/phone; the account is the identity).
Common Error Scenarios
400: invalid numeric path param401: missing or invalid JWT422: invalid category/body validation