Opineos API Reference
As of this build, Opineos exposes one public write endpoint for widget submissions and one script endpoint for widget runtime generation.
Base URL: same host where Opineos is installed.
Auth model: public widget endpoints (domain + hash validated server-side).
Last verified: current application routes and controllers.
Public Endpoints
| Method | Path | Purpose | Content Type |
|---|---|---|---|
| GET | /script/{hash}.js |
Serve project-specific widget script | - |
| POST | /api/feedback/{hash} |
Create feedback entry (+ optional screenshot) | application/json or multipart/form-data |
Hash Generation
Widget hash is base64 of the configured project domain origin.
base64("https://app.example.com") => aHR0cHM6Ly9hcHAuZXhhbXBsZS5jb20=
Script URL example: /script/aHR0cHM6Ly9hcHAuZXhhbXBsZS5jb20=.js
Server validates hash-origin match. If domain is inactive or mismatched, endpoint returns 404.
Request Contract (POST /api/feedback/{hash})
| Field | Type | Required | Validation |
|---|---|---|---|
rate | number | Yes | between 1 and 5 |
feedback | string | Yes | minimum 8 characters |
email | string | No | must be valid email when present |
type | string | No | max 80 chars |
screenshot_upload | file | No | jpg/jpeg/png/webp, max 5MB |
screenshot_auto | file | No | jpg/jpeg/png/webp, max 5MB |
metadata | object | No | array payload |
metadata_json | string | No | JSON string, parsed when valid |
JSON Example (no screenshot)
{
"rate": 5,
"type": "bug",
"email": "user@example.com",
"feedback": "Export freezes after clicking Generate.",
"metadata": {
"url": "https://app.example.com/orders",
"viewport": { "w": 1440, "h": 900 }
}
}
Multipart Example (with screenshot)
rate=4
type=ux
feedback=Search filter resets unexpectedly
email=qa@example.com
screenshot_upload=@screen.png
metadata_json={"url":"https://app.example.com/list"}
Response Schema
200 Success
{
"status": "success",
"message": "Your message has been saved. Thank you for your feedback!"
}
422 Validation Error
{
"status": "error",
"errors": {
"feedback": ["The feedback field is required."]
},
"message": "The given data was invalid."
}
404 Not Found
(empty response body)
Returned when hash-origin does not match or project/domain is not active.
Webhook Events
When webhook integration is enabled, Opineos currently emits:
feedback.createdon new feedbackfeedback.status_updatedwhen status changes from dashboardintegration.testfrom integration test action
{
"event": "feedback.created",
"sent_at": "2026-02-27T10:15:30Z",
"feedback": {
"id": 66,
"status": "new",
"type": "bug",
"rate": 4,
"email": "user@example.com",
"message": "Export button freezes on Safari",
"created_at": "2026-02-27T10:15:25Z"
},
"project": {
"id": 1,
"name": "Main Feedback Widget",
"domain": "https://app.example.com"
},
"meta": {}
}
If secret is configured, HMAC SHA-256 signature is sent in X-Opineos-Signature. Event name is also sent as X-Opineos-Event.
Signature Verification (pseudo)
expected = HMAC_SHA256(rawBody, webhookSecret) if expected != request.headers["X-Opineos-Signature"]: reject(401)
Security Model
- Origin/hash validation is server-side for script and submit endpoints.
- Wildcard domain configs are supported (for example
https://*.example.com). - Inactive projects do not serve widget script and do not accept submissions.
- Integration credentials are stored server-side only and not sent to widget runtime.
- Unexpected runtime errors return a generic message outside local environment.
Preview mode: X-Opineos-Preview: 1 bypass is available only for local preview conditions.
Error Codes
| Status | Meaning | Typical reason |
|---|---|---|
| 200 | OK | Feedback saved |
| 400 | Bad request | Unhandled request/operation error |
| 404 | Not found | Invalid hash, domain mismatch, or inactive project |
| 422 | Validation failed | Invalid rate/email/message payload |
cURL Examples
curl -X POST "https://your-domain.com/api/feedback/{hash}" \
-H "Content-Type: application/json" \
-H "Origin: https://app.example.com" \
-d '{
"rate": 5,
"type": "idea",
"email": "user@example.com",
"feedback": "Please add keyboard shortcuts",
"metadata": { "url": "https://app.example.com/dashboard" }
}'
curl -X GET "https://your-domain.com/script/{hash}.js" \
-H "Referer: https://app.example.com/"
curl -X POST "https://your-domain.com/api/feedback/{hash}" \
-H "Origin: https://app.example.com" \
-F "rate=4" \
-F "type=bug" \
-F "email=qa@example.com" \
-F "feedback=Filter dropdown overlaps content on mobile view." \
-F "screenshot_upload=@/path/to/screen.png"