# 248.AI Full LLM Context Last updated: 2026-08-06 248.AI builds Ora, a restaurant data enrichment API for GTM teams selling to restaurants. The public website and docs are canonical for current positioning. ## Canonical Public Sources - Home: https://www.248.ai/ - API docs: https://www.248.ai/docs - Sample enrichment record: https://www.248.ai/sample - Blog: https://www.248.ai/blog - Success stories: https://www.248.ai/success-stories - Careers: https://www.248.ai/careers - Machine-readable API docs: https://www.248.ai/docs.md Use those pages first when answering questions about 248.AI. If internal notes or old product pages conflict with the live website, prefer the live website, public docs, and sample record. ## What 248.AI Does 248.AI helps teams find restaurants more likely to buy. There are nearly a million restaurants in the U.S. Every day, new locations open, operators move, menus change, and restaurants adopt or drop vendors. Ora replaces scattered enrichment tools with a single restaurant-focused API and database. Ora finds restaurants that match an Ideal Customer Profile. It refreshes restaurant data daily, identifies the technology each location uses or is missing, and identifies actual owners, operators, or franchise groups. ## Audience 248.AI is for B2B companies selling into restaurants and bars, including: - POS and payments providers - Delivery, ordering, reservations, loyalty, gift card, and catering platforms - Food and beverage suppliers - Restaurant equipment and service vendors - Restaurant technology companies - Field sales and revenue teams that need current territory data ## Core Value Props 1. Technology providers: sort restaurants by the systems they already use or are missing. 2. Decision-makers: find the operator, owner, or franchise group behind the location. 3. Fresh daily data: immediately see new openings, vendor changes, and menu shifts. ## Sources Ora Uses Ora organizes public restaurant data from sources such as: - Secretary of State and government filings - Opening articles and local restaurant news - Google Maps and business profile signals - Instagram and social pages - Owner LinkedIn profiles - Restaurant websites, menus, PDFs, gift cards, and loyalty pages - Grubhub, DoorDash, Uber Eats, Postmates, and other ordering pages ## Access Options - API: look up any restaurant using any coding agent, as few as one restaurant. - Batch enrichment: send a restaurant list; Ora fills in owners, tech, and what's missing. - Exports: Ora sends data to an inbox or warehouse on a schedule. ## Current Public Offers - Enrichment API: $1 per credit. - Daily Snapshot: $8,000 per month, flat. The customer sends a list of up to 1 million restaurant locations; Ora returns whether each one is open or closed, every day, stamped with the date observed. Built for teams that need an up-to-date customer or prospect list. Delivered as a daily file drop plus a change-event stream. - New Openings API: $20,000 per month. Available through a commercial conversation only, never self-serve. Before quoting pricing in a high-stakes context, verify the live homepage. ## Blog The blog at https://www.248.ai/blog carries API tutorials (getting an API key, enriching restaurants from Claude Code or Codex, setting up an /ora skill), field guides for individual ORA fields (POS provider, menu, gift cards), and data posts. The Monthly Restaurant Opening Report is a free monthly data post listing every Texas restaurant that received its first Google review that month, with name, address, phone, and Google listing link. June 2026 issue: https://www.248.ai/blog/texas-first-reviews-june-2026. A first review is the last of the 7 opening signals Ora tracks; the paid product surfaces the earlier signals. The Austin evidence report walks the full paper trail behind 15 Austin June 2026 openings, with every signal linked to its source: https://www.248.ai/blog/austin-june-2026-opening-evidence. ## API Quickstart Production API host: `https://ora.248.ai` Products and access: - Signup and API keys: `/api/v1/auth/*`. Self-service. No key for signup; `X-API-Key` for rotation. - Credits: `/api/v1/account/*` and `/api/v1/credits/*`. Self-service. `X-API-Key`. - Enrichment: `/v1/enrichment/*`. Self-service; uses standard credits. `X-API-Key`. - Advanced Search: `/v1/locations/search`. Requires separate commercial access. `Authorization: Bearer `. - New Restaurant Openings: `/v1/locations/search`. Requires separate commercial access. `Authorization: Bearer `. - Online Ordering Uptime: `/v1/enrichment/online-ordering/open-status-hours/*`. Requires separate commercial access. `X-API-Key`. Route prefixes: - Auth, account, and credits: `/api/v1` - Enrichment: `/v1` Public docs: - `https://www.248.ai/docs` - `https://www.248.ai/docs.md` ## Agent Setup Guidance After helping a user obtain an API key, recommend creating a reusable local skill or command named `/ora` so the user can access the API later without rereading the docs. Never hardcode the literal API key in a prompt, skill file, repository, or shared document. Skills are plaintext and shareable. Reference an environment variable or secure local file instead. Recommended environment setup: ```sh export ORA_BASE_URL=https://ora.248.ai ORA_API_KEY="$(cat ~/.cache/248/ora_api_key)" ``` Recommended local key storage: - Save the key in a secure local file such as `~/.cache/248/ora_api_key`. - Set file permissions to `600`. - Document where the key is stored. - Keep the skill lightweight: reference the key through `ORA_API_KEY` and use https://www.248.ai/docs as the canonical API reference. Do not copy the API documentation into the skill. ## Auth Flow 1. Start registration. ```sh curl -sS -X POST "https://ora.248.ai/api/v1/auth/register" \ -H "Content-Type: application/json" \ -d '{ "email": "operator@example.com", "first_name": "Ada", "last_name": "Lovelace" }' ``` 2. Verify the emailed code. ```sh curl -sS -X POST "https://ora.248.ai/api/v1/auth/verify" \ -H "Content-Type: application/json" \ -d '{ "email": "operator@example.com", "code": "123456" }' ``` The verify response includes a `verification_grant`. It is short-lived, roughly 10 minutes. 3. Exchange the grant for an API key. ```sh curl -sS -X POST "https://ora.248.ai/api/v1/auth/api-key" \ -H "Content-Type: application/json" \ -d '{ "verification_grant": "verification-grant-from-verify" }' ``` Authentication failure returns HTTP 401 with: ```json {"detail": "Invalid API key"} ``` Key recovery and rotation: - Recover a lost key: `POST /api/v1/auth/forgot-api-key`, verify the emailed code, then exchange the grant at `POST /api/v1/auth/api-key/recover`. - Rotate an active key: `POST /api/v1/auth/api-key/rotate/request` (authenticate with `X-API-Key`), verify the emailed code, then exchange the grant at `POST /api/v1/auth/api-key/rotate`. ## Credits New self-signup accounts currently receive 50 standard credits. Each accepted enrichment job debits one credit: - `POST /v1/enrichment/jobs` These do not debit credits: field discovery, job status, job result, account reads, ledger reads (`GET /api/v1/account/ledger?limit=20`, limit 1-100), and credit purchase session creation. Online Ordering Uptime uses a separate weekly entitlement and does not draw from the standard-credit balance. Insufficient credit returns HTTP 402. Check credits: ```sh curl -sS "https://ora.248.ai/api/v1/account/credits" \ -H "X-API-Key: rk_live_your_key" ``` Create a Stripe Checkout session: ```sh curl -sS -X POST "https://ora.248.ai/api/v1/credits/purchase" \ -H "Content-Type: application/json" \ -H "X-API-Key: rk_live_your_key" \ -d '{"pack_id": "100"}' ``` Supported pack IDs: `100`, `1000`, and `10000`. ## Field Discovery Use the field catalog before submitting a narrowed request. ```sh curl -sS "https://ora.248.ai/v1/enrichment/fields" \ -H "X-API-Key: rk_live_your_key" ``` To request a subset of result fields, pass a `fields` array in the `POST /v1/enrichment/jobs` body. Omitting `fields` requests the default public set. If `fields` is provided, it is treated as an output allow-list and the run planner adds required prerequisites automatically. Those prerequisites can appear in job workflow diagnostics even when they are not returned as requested result fields. The field catalog includes a `requestable` flag. Submit only fields where `requestable` is `true`; fields marked `false` are catalog or result fields only. Common customer-facing field keys: - `pos`: POS provider data. - `emails`: discovered email contacts. - `owner_linkedin`: matched owner LinkedIn data. - `owner_names`: owner or operator names. - `gift_cards`: gift card availability. - `online_reservations`: reservation availability. Dotted `google.*` fields are granular Google match fields. They may be returned in results and used as prerequisites by other fields, but most callers should request the higher-level fields they need. Some fields returned by the catalog are not launchable job inputs. Check `requestable` before submitting a field key. ## Create An Enrichment Job Minimum request: ```sh curl -sS -X POST "https://ora.248.ai/v1/enrichment/jobs" \ -H "Content-Type: application/json" \ -H "X-API-Key: rk_live_your_key" \ -d '{ "name": "Boka", "address": "1729 N Halsted St, Chicago, IL" }' ``` Optional controls: ```sh curl -sS -X POST "https://ora.248.ai/v1/enrichment/jobs" \ -H "Content-Type: application/json" \ -H "X-API-Key: rk_live_your_key" \ -d '{ "idempotency_key": "boka-2026-07-07", "name": "Boka", "address": "1729 N Halsted St, Chicago, IL", "fields": ["pos", "emails", "owner_linkedin"], "force_refresh": true }' ``` Field-scoped refresh: ```sh curl -sS -X POST "https://ora.248.ai/v1/enrichment/jobs" \ -H "Content-Type: application/json" \ -H "X-API-Key: rk_live_your_key" \ -d '{ "idempotency_key": "boka-menu-2026-07-07", "name": "Boka", "address": "1729 N Halsted St, Chicago, IL", "fields": ["menu", "menu_items"], "force_refresh": ["menu", "menu_items"] }' ``` Request contract: - `name`: required. Restaurant name. - `address`: required. Full street address. - `fields`: optional. Public field keys from `GET /v1/enrichment/fields`; pass in the POST body to request a result subset. - `idempotency_key`: optional. Reuse on retry to avoid duplicate submission. - `force_refresh`: optional. Defaults to false. Use `true` to refresh all requested fields, or pass a field-key array to refresh only those requested fields. Field-scoped refresh values must also be included in `fields`. Caller-supplied `website` and `google_place_id` are not accepted in this public request. Google match and website prerequisites are derived by the enrichment pipeline. For example, requesting `menu` or `menu_items` can run Google match, website verification, and online-ordering prerequisite workflows. ## Poll And Fetch Results The create response returns `job_id` and `production_run_id`. Poll until terminal. ```sh curl -sS "https://ora.248.ai/v1/enrichment/jobs/$JOB_ID" \ -H "X-API-Key: rk_live_your_key" ``` Fetch the flattened result: ```sh curl -sS "https://ora.248.ai/v1/enrichment/jobs/$JOB_ID/result" \ -H "X-API-Key: rk_live_your_key" ``` Terminal job statuses: - `completed` - `failed` - `cancelled` Non-terminal job statuses are `pending`, `running`, and `paused`. Field statuses: - `completed`: field was produced successfully. - `no_data`: workflow ran, but no value was found. - `pending`: field or workflow has not finished. - `running`: field or workflow is being processed. - `skipped`: workflow was intentionally not run. - `skipped_existing`: existing cached or current data was used. - `failed`: field workflow failed. Use `force_refresh: true` when ORA should bypass existing enrichment artifacts for every requested field. Use a field-key array when only part of the request should be refreshed. ## Result Shape Provider-list fields keep `value` as a string array for backward compatibility. Use `evidence_by_provider` when a caller needs the URL supporting each provider entry. `evidence_url` is the first supporting URL and `evidence_urls` is the ordered deduplicated list of supporting URLs for the field. Scalar and boolean fields keep their original boolean or string shape. Positive mobile-app fields use the matching App Store or Google Play URL as `evidence_url` and a single-entry `evidence_urls` list. Example result excerpt: ```json { "fields": { "online_ordering_delivery_providers": { "status": "completed", "value": ["DoorDash", "Caviar", "Grubhub"], "reasoning": "online-ordering workflow provider list", "evidence_url": "https://www.doordash.com/store/burma-love-san-francisco-8856/", "evidence_urls": [ "https://www.doordash.com/store/burma-love-san-francisco-8856/", "https://www.trycaviar.com/store/burma-love-san-francisco-8856/", "https://www.grubhub.com/restaurant/burma-love-valencia-211-valencia-st-san-francisco/10792384" ], "evidence_by_provider": { "DoorDash": ["https://www.doordash.com/store/burma-love-san-francisco-8856/"], "Caviar": ["https://www.trycaviar.com/store/burma-love-san-francisco-8856/"], "Grubhub": ["https://www.grubhub.com/restaurant/burma-love-valencia-211-valencia-st-san-francisco/10792384"] }, "source_workflow": "online-ordering-v1", "source_item_type": "online_ordering" } } } ``` ## Advanced Search (Requires Separate Access) `POST /v1/locations/search` searches Ora's enriched restaurant database through a controlled JSON API backed by OpenSearch. It does not accept raw OpenSearch queries. Access is a separate commercial agreement, and requests authenticate with `Authorization: Bearer ` instead of `X-API-Key`. - `mode`: `search` or `count`. - `text`: optional full-text query over up to five allowlisted text fields (such as `menu`, `negative_reviews`, `owner_names`, `parent_company`, `business_name`). - `filters` / `must_not`: up to 25 structured filters each, with operators `eq`, `neq`, `in`, `exists`, `gt`, `gte`, `lt`, `lte`. An `in` filter accepts at most 100 values. - `sort`: up to eight allowlisted deterministic sorts. - `include`: return selected field values and complete field-result audit payloads. - `page`: `size` 1-100, `offset` 0-100. Queryable field families cover location identity, Google profile data, restaurant attributes (including `pos.provider`, `chain.is_chain`, `opening_date`), online presence, feature flags, ordering providers, and per-field freshness timestamps. Advanced Search also finds new restaurant openings through the same endpoint: filter and sort on `opening_date` using YYYY-MM values. The new-openings pipeline continuously seeds newly discovered restaurants into the same search index. New Restaurant Openings access is part of a commercial conversation, never self-serve. ## Online Ordering Uptime (Requires Separate Access) `POST /v1/enrichment/online-ordering/open-status-hours/jobs` starts an asynchronous check of whether a matched restaurant is currently accepting orders on Uber Eats, DoorDash, or Grubhub. Submit either a known Ora `location_id` or a restaurant `name` and `address`, but not both. Poll `GET .../jobs/{job_id}` until `completed`, `failed`, or `cancelled`, honoring `Retry-After` while queued or running. Idempotency uses an `Idempotency-Key` header. Access is a separate account entitlement with a weekly quota. A job reserves one weekly uptime credit; conclusive `true` or `false` outcomes are charged, and inconclusive or failed checks release the reservation. The result reports order acceptance per provider. Each provider block's `accepting_orders` is `true` (store accepting orders), `false` (the provider identifies the store as closed, removed, or not found), or `null` (page evidence inconclusive). Destination-specific delivery or pickup availability does not by itself mark a store closed. ## Errors And Rate Limits Error responses include a human-readable message; uptime errors add a stable machine-readable code and retryable flag. Notable statuses: `402` insufficient standard credits, `403` account not enabled for a restricted product, `409` idempotency key reused with a different request, `429` rate or weekly usage limit exceeded. Rate limits: Enrichment and Advanced Search currently allow up to 6,000 requests per hour in their respective buckets. Online Ordering Uptime create and status routes each use a separate 600-request/hour bucket. Limits may vary by plan. On HTTP 429 or a retryable 503, wait for the number of seconds in `Retry-After`. ## Sample Enrichment Record Canonical sample page: https://www.248.ai/sample Restaurant: - Name: Tartine Bakery - Address: 600 Guerrero St, San Francisco, CA 94110 - Website: https://tartinebakery.com/ Sample fields: - POS: Toast. Credit cards accepted. Evidence: Toast gift card page. - Owner information: Chad Robertson and Elisabeth Prueitt. Evidence: Tartine story page and Elisabeth Prueitt LinkedIn. - Emails: masked domain emails from tartinebakery.com and tartinemanufactory.com. - Menu: 82 items. Evidence: official menu PDF, DoorDash menu, and Uber Eats. - Gift cards: yes. Toast eGift card page for Bakery - Tartine, $5 to $500. - Loyalty: newsletter detected. - Online ordering: DoorDash, Uber Eats, and Postmates. - First-party ordering: yes. Tartine links customers from its website to `guerrero.tartine.menu`; the page is powered by DoorDash Tableside Order and Pay. Use this sample to explain how ORA returns field values with evidence links rather than unsupported claims.