
POS integration API
Send complete sales-report snapshots to VenueGain AI and retrieve the resulting analysis. Imported reports appear in the venue’s Overview, Sales & menu, Opportunities and Weekly reports. This API does not call the AI coach or execute business decisions.
Base URL: https://venuegainai.com/api/v1 · Version 1
1. Authorize a connection
The customer creates their venue, accepts the current agreement and activates a subscription or trial. In My venues, open Connect POS / API keys, name the connection and create a key. The full key is shown once; store it securely on the POS provider’s server. Keys are restricted to one venue, expire after 90 days and can be revoked immediately. An active subscription or trial remains required for each API request. Owner accounts have separate testing access.
Authorization: Bearer YOUR_VENUE_API_KEY Accept: application/json Content-Type: application/json
Use HTTPS. Do not put keys in query strings, client-side JavaScript, public repositories or logs. API keys cannot manage subscriptions, create venues, delete customer accounts or read other venues. Browser sessions are not accepted as API credentials. No cross-origin browser access is provided; connect from your backend.
2. Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /venue | Confirm the key’s venue and currency. |
| POST | /reports | Import and analyze a complete snapshot. |
| GET | /reports?limit=20&offset=0 | List the venue’s saved report summaries. |
| GET | /reports?id=REPORT_ID | Retrieve one saved report and its analysis. |
List limit: 1–50. Offset: 0–10000. Responses include pagination.hasMore. Reports are separate snapshots; the dashboard uses the selected report, rather than adding overlapping reports together.
3. Sales format
Requests contain 10–20,000 line-item rows, up to 8 MB of UTF-8 JSON and at most one year of sales dates. Send dates and times in the venue’s local time and monetary amounts as decimal major currency units, such as 12.50 USD. Currency must match the venue. Exclude refunds, voided transactions, negative sales, guest personal information and card details. Every request is validated as a whole; invalid requests are rejected without saving a partial report.
| Field | Requirement |
|---|---|
| externalReportId | Required; a stable unique snapshot identifier, up to 120 characters. |
| currency | USD, THB, EUR, GBP, SGD or AUD; matches the venue. |
| name | Optional report label, up to 160 characters. |
| rows[].lineId | Required; unique within this snapshot, up to 120 characters. |
| rows[].date | Required valid YYYY-MM-DD date. |
| rows[].item | Required menu item name, up to 150 characters. |
| rows[].netSales | Required nonnegative line total, after discounts. The report must have positive total sales. |
| rows[].quantity | Positive number; defaults to 1. |
| rows[].lineCost | Optional nonnegative ingredient cost for the entire line, not unit cost. |
| rows[].time | Optional HH:mm local time. |
| rows[].orderId | Optional receipt/order identifier, up to 120 characters. |
| rows[].category | Food, Beverage or Unclassified; defaults to Unclassified. |
{
"externalReportId": "pos-2026-10-07-example-v1",
"currency": "USD",
"name": "Daily POS sales",
"rows": [
{
"lineId": "line-1",
"date": "2026-10-07",
"item": "Lunch dish",
"quantity": 1,
"netSales": 12,
"orderId": "order-1",
"category": "Food"
},
{
"lineId": "line-2",
"date": "2026-10-07",
"item": "House drink",
"quantity": 1,
"netSales": 5,
"orderId": "order-1",
"category": "Beverage"
},
{
"lineId": "line-3",
"date": "2026-10-07",
"item": "Lunch dish",
"quantity": 1,
"netSales": 12,
"orderId": "order-2",
"category": "Food"
},
{
"lineId": "line-4",
"date": "2026-10-07",
"item": "House drink",
"quantity": 1,
"netSales": 5,
"orderId": "order-2",
"category": "Beverage"
},
{
"lineId": "line-5",
"date": "2026-10-07",
"item": "Lunch dish",
"quantity": 1,
"netSales": 12,
"orderId": "order-3",
"category": "Food"
},
{
"lineId": "line-6",
"date": "2026-10-07",
"item": "House drink",
"quantity": 1,
"netSales": 5,
"orderId": "order-3",
"category": "Beverage"
},
{
"lineId": "line-7",
"date": "2026-10-07",
"item": "Lunch dish",
"quantity": 1,
"netSales": 12,
"orderId": "order-4",
"category": "Food"
},
{
"lineId": "line-8",
"date": "2026-10-07",
"item": "House drink",
"quantity": 1,
"netSales": 5,
"orderId": "order-4",
"category": "Beverage"
},
{
"lineId": "line-9",
"date": "2026-10-07",
"item": "Lunch dish",
"quantity": 1,
"netSales": 12,
"orderId": "order-5",
"category": "Food"
},
{
"lineId": "line-10",
"date": "2026-10-07",
"item": "House drink",
"quantity": 1,
"netSales": 5,
"orderId": "order-5",
"category": "Beverage"
}
]
}The original rows are processed but not stored as individual transactions. We save the analysis, report metadata and a payload hash for duplicate protection. Food and Beverage panels require categories; costs, times and order IDs enable additional analysis.
4. Duplicate protection and corrections
Reuse the same externalReportId when retrying the same snapshot. The first successful import returns HTTP 201 and replayed: false. An identical retry returns HTTP 200, replayed: true and the same report ID, without creating a second report. Row order can change on a retry. Keep all field values, the report name and optional fields consistent.
If the identifier exists with different data, the API returns HTTP 409. For a corrected snapshot, send a new versioned identifier, such as pos-2026-10-07-v2. The newer snapshot becomes a separate selectable report. This API does not append transactions to an earlier report, automatically merge reports or deduplicate lines across different snapshot identifiers.
5. Responses, limits and retries
{
"data": {
"id": "REPORT_ID",
"externalReportId": "pos-2026-10-07-example-v1",
"created": "2026-10-07T01:00:00.000Z",
"analysis": {
"total": 85,
"rows": 10,
"start": "2026-10-07",
"end": "2026-10-07"
}
},
"replayed": false
}Successful report responses contain the complete analysis; this example is abbreviated. List responses contain summaries. Limits are 60 requests per key per minute, including up to five import attempts. HTTP 429 includes Retry-After: 60. Retry 429, network failures and 503 with backoff and the same externalReportId. Fix 400, 413, 415, 422 or 409 requests before retrying. Revoke and replace compromised keys.
{
"error": {
"code": "unauthorized",
"message": "The API key is invalid, expired or revoked."
}
}HTTP 401: missing, invalid, expired or revoked key. HTTP 403: customer agreement or subscription required. HTTP 404: report not found for the key’s venue. HTTP 413: body exceeds 8 MB. HTTP 415: wrong content type. HTTP 422: invalid sales data or currency mismatch.
6. Example request
curl https://venuegainai.com/api/v1/reports \ -H "Authorization: Bearer $VENUEGAIN_API_KEY" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ --data-binary @report.json
Your POS provider still needs to implement or configure a connector using this format. Creating an API key does not automatically connect a POS. Contact info@venuegainai.com for integration questions.