Skip to main content
The Vori REST API lets grocers pull and manage data like store products programmatically. All requests go to https://api.vori.com.

Authentication

If you or the integration consuming this API only need to read data, create a user with the Read-only role at the banner level and authenticate with that account instead of a full-access one. This avoids errors from write attempts you didn’t anticipate needing, and limits the blast radius if the credentials are mishandled.
Every API request must include a bearer token in the Authorization header. Get one by exchanging your Vori login email and password for a token via Google’s Identity Toolkit:
1

Request a token

Send a POST request to:
with a JSON body containing your Vori credentials:
Example using curl:
2

Extract the token

The response is a JSON object that includes an idToken field. This is your bearer token — use it in the Authorization header of subsequent requests to https://api.vori.com:
Tokens expire after an hour, so you’ll need to repeat this exchange periodically rather than hardcoding a token indefinitely.

Use the refresh token instead of re-authenticating

The verifyPassword response also includes a refreshToken field. Instead of resending your email and password every hour, exchange that refresh token for a new idToken via Google’s secure token endpoint:
with a JSON body:
Example using curl:
The response contains a new id_token (your bearer token) and a new refresh_token — store the new refresh token for the next exchange, since the old one may be rotated.
This uses Google Identity Toolkit’s standard secure token exchange rather than a Vori-specific endpoint. Verify the response field names (id_token, refresh_token) against what you receive, since Google’s REST API is documented outside of Vori’s own docs.

Pagination, filtering, and sorting

List endpoints like /v1/store-products accept a state query parameter: a URL-encoded JSON object that controls which rows come back, how they’re ordered, and how many are returned at once. Within that JSON object, only startRow, endRow, filterModel, and sortModel are supported — all other properties are rejected. This is separate from other query parameters an endpoint may support.
PaginationstartRow and endRow select which slice of results to return: startRow defaults to 0, and endRow defaults to startRow plus 10. You can request at most 1000 rows at a time (endRow - startRow <= 1000). The response’s rowCount field always reflects the total number of matching rows across the entire result set, not just the rows returned in this request. SortingsortModel orders results by any filterable field, plus id. If you don’t specify a sortModel, results are sorted by created_at descending (e.g., newest first). FilteringfilterModel is an object keyed by field name, where each value describes how to match that field: type is optional for set and boolean filters and defaults to in. Boolean fields also accept set filters, and date fields also accept "filterType": "datetime". Which fields are filterable, and which filter types each supports, varies by endpoint. Example: active products in a specific store, sorted by price, 50 at a time:
Filtering by an unsupported field, or sending a state shape outside of startRow, endRow, filterModel, and sortModel, returns a 400 error naming the unsupported field.