Opineos logo Opineos
Start Now
Current Backend

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
ratenumberYesbetween 1 and 5
feedbackstringYesminimum 8 characters
emailstringNomust be valid email when present
typestringNomax 80 chars
screenshot_uploadfileNojpg/jpeg/png/webp, max 5MB
screenshot_autofileNojpg/jpeg/png/webp, max 5MB
metadataobjectNoarray payload
metadata_jsonstringNoJSON 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.created on new feedback
  • feedback.status_updated when status changes from dashboard
  • integration.test from 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
200OKFeedback saved
400Bad requestUnhandled request/operation error
404Not foundInvalid hash, domain mismatch, or inactive project
422Validation failedInvalid 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"