Looker & Looker Studio
Looker and Looker Studio don't consume REST APIs directly — they connect to databases, warehouses, and spreadsheets. So an OmniCart → Looker setup always has the same shape:
OmniCart API ──(scheduled pull)──▶ storage Looker can read ──▶ Looker / Looker StudioThis guide covers both paths: the lightweight one (Looker Studio + Google Sheets) and the production one (a warehouse + Looker/Looker Studio).
Path A — Looker Studio via Google Sheets (fastest)#
Good for a daily KPI dashboard with no infrastructure.
1. Schedule a daily metrics pull into a Sheet. In Google Sheets, add an Apps Script (Extensions → Apps Script) with a daily time-driven trigger:
function pullDailyMetrics() {
// Secret API key (Settings → API Key Management). Store it in
// Script Properties rather than hard-coding it in the script.
const apiKey = PropertiesService.getScriptProperties().getProperty('OMNICART_API_KEY');
const day = new Date(Date.now() - 24 * 3600 * 1000);
const start = Utilities.formatDate(day, 'UTC', "yyyy-MM-dd'T'00:00:00'Z'");
const end = Utilities.formatDate(day, 'UTC', "yyyy-MM-dd'T'23:59:59'Z'");
const resp = UrlFetchApp.fetch(
`https://your-store.omnicart.cc/admin/metrics?startDate=${start}&endDate=${end}&comparison=none`,
{ headers: { Authorization: 'Basic ' + Utilities.base64Encode(apiKey + ':') } }
);
const cards = JSON.parse(resp.getContentText()).metrics.summary.cards;
const get = id => (cards.find(c => c.id === id) || {}).value;
SpreadsheetApp.getActive().getSheetByName('daily_kpis').appendRow([
start.slice(0, 10),
get('total_revenue'),
get('total_orders'),
get('average_order_value'),
get('total_refunded'),
]);
}2. Connect Looker Studio to the Sheet (Create → Data source → Google Sheets), set the date column's type to Date, and build your charts. Set money columns to Currency — values are already decimal dollars.
For order-level detail in Sheets, do the same with GET /admin/orders (one row per order) — but past a few tens of thousands of rows, move to Path B.
Path B — Warehouse + Looker (production)#
For real modeling (LookML), order-level exploration, and joins against ad-spend or other sources, land OmniCart data in a warehouse (BigQuery, Snowflake, Postgres, Redshift) and connect Looker to that.
1. Build the sync job. A script on any scheduler (cron, Cloud Functions, Airflow) that:
- Authenticates with a secret API key (
-u "sk_...:"— see Data Access Overview); if using JWTs instead, re-authenticate each run. - Pulls
GET /admin/orderswith anupdated_at[$gte]=<cursor>filter,order=updated_at,limit=100, paging byoffset— full pattern in Pulling Orders Data. - Requests the fields you'll model:
fields=id,display_id,status,email,customer_id,total,currency_code,created_at,updated_at,sales_channel_id,*items(drop*itemsif you only need order-level grain). - Upserts into the warehouse by
id, then advances the cursor to the maxupdated_atseen.
Suggested orders table schema:
| Column | Type | Source |
|---|---|---|
order_id |
STRING (PK) | id |
display_id |
INTEGER | display_id |
status |
STRING | status |
email |
STRING | email |
customer_id |
STRING | customer_id |
total |
NUMERIC(12,2) | total — decimal dollars, load as-is |
currency_code |
STRING | currency_code |
sales_channel_id |
STRING | sales_channel_id |
created_at |
TIMESTAMP (UTC) | created_at |
updated_at |
TIMESTAMP (UTC) | updated_at |
Line items, if you need product-level grain, go to a child table (order_id, sku, title, quantity, unit_price) fed from *items.
2. Backfill history. For the initial load, either loop the same pull with created_at windows month by month, or use the async bulk CSV export (POST /admin/orders/export) and load the delivered file — details and its Eastern-calendar-day date semantics in Pulling Orders Data.
3. Model in Looker. Connect the warehouse, then define a view over the orders table. Typical starting measures:
view: orders {
dimension: order_id { primary_key: yes sql: ${TABLE}.order_id ;; }
dimension_group: created { type: time timeframes: [date, week, month] sql: ${TABLE}.created_at ;; }
dimension: status { sql: ${TABLE}.status ;; }
dimension: sales_channel_id { sql: ${TABLE}.sales_channel_id ;; }
measure: total_orders { type: count }
measure: total_revenue { type: sum sql: ${TABLE}.total ;; value_format_name: usd }
measure: average_order_value { type: average sql: ${TABLE}.total ;; value_format_name: usd }
}Filter status to exclude canceled orders in revenue measures to match the OmniCart dashboard's numbers.
Reconciliation#
Whichever path you use, validate the pipeline by comparing a fixed day against OmniCart's own numbers: GET /admin/metrics for that day (total_revenue, total_orders cards — see Metrics & Reports API). Small deltas usually mean timezone bucketing (your warehouse day vs. the query window) or canceled-order handling; a 100× delta means a cents conversion was applied to already-decimal totals.