VenueGain AI

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

MethodPathPurpose
GET/venueConfirm the key’s venue and currency.
POST/reportsImport and analyze a complete snapshot.
GET/reports?limit=20&offset=0List the venue’s saved report summaries.
GET/reports?id=REPORT_IDRetrieve 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.

FieldRequirement
externalReportIdRequired; a stable unique snapshot identifier, up to 120 characters.
currencyUSD, THB, EUR, GBP, SGD or AUD; matches the venue.
nameOptional report label, up to 160 characters.
rows[].lineIdRequired; unique within this snapshot, up to 120 characters.
rows[].dateRequired valid YYYY-MM-DD date.
rows[].itemRequired menu item name, up to 150 characters.
rows[].netSalesRequired nonnegative line total, after discounts. The report must have positive total sales.
rows[].quantityPositive number; defaults to 1.
rows[].lineCostOptional nonnegative ingredient cost for the entire line, not unit cost.
rows[].timeOptional HH:mm local time.
rows[].orderIdOptional receipt/order identifier, up to 120 characters.
rows[].categoryFood, 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.