Feedback
Let users send free-form feedback (bug reports, suggestions, confusion about a result) along with a screenshot of what they were looking at when they hit "Send feedback". The feedback is delivered by email to the VPT team for triage.
Overview
submitFeedback is intentionally simple in its first
iteration:
- The user types a description of their feedback.
- Your app captures a PNG screenshot of the current screen and base64-encodes it.
-
You POST both to
submitFeedbackalong with optional context (app version, device, route, etc.). -
The server emails everything (with the screenshot attached) to the
VPT team and returns an opaque
FeedbackIdthe user can quote.
The current implementation does not persist
feedback to the database. It is delivered by email only. A future
phase will add a user_feedback table and an admin
dashboard alongside the existing
Query Reports
dashboard. The request/response shape will not change.
submitFeedback uses the same authentication scheme as
reportQuery: the user
must be logged in, and the request must include their session
credential as api_key in the body. The
dev_key is also required at the gateway.
X-VPT-Log-Id as logId to
connect the feedback to a specific previous API call.
submitFeedback
Submit user feedback with an attached screenshot. Delivered by email; no DB row is created in Phase 1.
/api
Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Required | application/json |
Request Body
{
"query": "submitFeedback",
"dev_key": "your_developer_key",
"api_key": "user_session_api_key",
"data": {
"description": "After computing takeoff for LFPG 27R the V1 displayed seems too low.",
"screenshotPng": "iVBORw0KGgoAAAANSUhEUgAA...", // base64-encoded PNG
"appVersion": "1.4.2 (build 312)",
"serverApiVersion": "1.3.6",
"deviceOs": "iOS 17.5",
"deviceModel": "iPhone 14 Pro",
"route": "TakeoffResults",
"logId": 12345,
"extras": {
"lastCalcId": "calc_98aa12"
}
}
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| query | string | Required | Must be "submitFeedback" |
| dev_key | string | Required | Your developer key |
| api_key | string | Required | The authenticated user's session api_key |
data object
|
|||
| description | string | Required | The user's feedback text (max 4 000 characters) |
| screenshotPng | string | Required |
Base64-encoded PNG of the current screen. A
data:image/png;base64, prefix is accepted and
stripped automatically. Decoded payload max 2 MB.
|
| appVersion | string | Optional | Your client app version string |
| serverApiVersion | string | Optional | The VPT API version your app is targeting |
| deviceOs | string | Optional | e.g. iOS 17.5, Android 14 |
| deviceModel | string | Optional | Device or browser model identifier |
| route | string | Optional | The screen / route the user was on when submitting |
| logId | integer | Optional |
An X-VPT-Log-Id from a previous response this
feedback relates to
|
| extras | object | Optional | Free-form key/value pairs reserved for future custom feedback forms. Included verbatim in the email body. |
Success Response
{
"Success": true,
"FeedbackId": "fb-9f3a17b2c4d8"
}
FeedbackId is an opaque short reference (no database
row is created in Phase 1). Show it to the user as a quotable
reference.
Error Responses
| Condition | Error message |
|---|---|
Missing or invalid api_key |
Authentication required to submit feedback. |
description empty |
Description is required. |
screenshotPng empty |
Screenshot (screenshotPng) is required. |
screenshotPng not valid base64 |
Screenshot is not valid base64. |
| Decoded screenshot > 2 MB | Screenshot too large (max 2 MB decoded). |
| Decoded payload not a PNG | Screenshot must be a valid PNG image. |
| More than 5 submissions in the past hour | Rate limit exceeded. Please wait before submitting more feedback. |
Full Example
// 1. Capture a PNG screenshot of the current screen.
// (Use html2canvas in browsers, or your platform's screenshot API.)
const canvas = await html2canvas(document.body);
const screenshotPng = canvas.toDataURL('image/png').split(',')[1]; // strip prefix
// 2. Submit feedback.
const response = await fetch('https://api.virtualperformancetool.com/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: 'submitFeedback',
dev_key: 'your_developer_key',
api_key: currentUserApiKey,
data: {
description: userFeedbackText,
screenshotPng,
appVersion: app.version,
serverApiVersion: '1.3.6',
deviceOs: platform.os,
deviceModel: platform.device,
route: currentRoute,
logId: lastResponseLogId // optional
}
})
});
const result = await response.json();
if (result.Success) {
showToUser(`Thanks! Feedback submitted (ref ${result.FeedbackId}).`);
} else {
showError(result.Error?.[0]?.Message ?? 'Unable to send feedback.');
}
Limits & Rate Limiting
| Limit | Value |
|---|---|
| Description length | 4 000 characters (truncated if longer) |
| Screenshot decoded size | 2 MB |
| Total request payload | ~3 MB recommended |
| Submissions per user | 5 per hour |
Keep the screenshot lean: scale to the device's logical resolution and prefer PNG-8 or compressed PNG. A typical phone screenshot is well under 500 KB.
Privacy
-
The user's
api_keyis consumed for authentication only and is never included in the email body. - The screenshot is sent as an email attachment to the VPT team and retained as long as the email is retained.
- Make it explicit in your client UI that submitting feedback attaches a screenshot of the current screen, so users can avoid sending sensitive content.
-
Feedback submissions are also logged in
api_query_logslike any other API call (subject to the standard 3-day retention plus auto-redaction ofapi_key,dev_key,passwordandtoken-named fields).
Integration Tips
- Surface a "Send feedback" entry point in a stable place (settings, help menu, or a long-press on the app's logo).
- When tapped, immediately capture a PNG screenshot of the current screen before presenting the feedback sheet (otherwise you'll just capture the sheet itself).
-
Show a sheet with:
- A thumbnail preview of the captured screenshot.
- A multi-line text field for the description (placeholder: "What's wrong, or what would you improve?").
- A clear note: "Your screenshot will be attached."
-
On submit, POST
submitFeedbackand store the returnedFeedbackId. -
Always pass
appVersion,deviceOs,deviceModeland the currentroute— these context fields drastically reduce triage time.
The feedback button should only be visible when a user is
authenticated, as the endpoint requires a valid
api_key. For anonymous contexts, link to the
support page instead.