What it is
A read-only API that lets a restaurant's own developers pull that restaurant's EatOutLog analytics into their own tools. It returns totals and averages only, never information that identifies an individual diner, and the same minimum group sizes as the owner dashboard apply. A restaurant needs the Insights plan and Data API access. Only the restaurant's owner can create credentials, on the Data API page of their owner settings.
Authentication
The API uses OAuth 2.0 client credentials. The owner creates a client and gets a client ID and a client secret (shown once). Swap them for an access token that lasts one hour, then send the token as a Bearer header. Ask for a new token when it expires.
curl -u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=client_credentials \
https://api.capypine.com/v1/oauth/token
{"access_token":"eol_at_...","token_type":"Bearer","expires_in":3600,"scope":"menu metrics.daily restaurants"}
curl -H "Authorization: Bearer $ACCESS_TOKEN" https://api.capypine.com/v1/restaurants
Secrets start with eol_cs_ and tokens with eol_at_. Never put either in a browser, an app or a public repository.
Scopes
restaurants: always granted.metrics.daily: daily figures for every covered restaurant.menu: menu and dish stats.insights: menu engineering, promotion results, quality alerts.benchmarks: comparisons with nearby restaurants.guests: repeat visitors, origin areas, reach and timing.questions: Ask your guests results.locations: comparison across the owner's locations.
Endpoints
Every response has as_of, the time the figures were computed. Restaurant responses also have time_zone; days are that restaurant's local days. A section the restaurant's plan doesn't include comes back as {"locked": true}. Detail sections accept days (28 to 365, default 30). Any average or rate for a group of fewer than 3 visits, ratings or diners comes back as null.
GET /v1/restaurants
Restaurants this client covers, and any it would cover except that their plan has lapsed (status not_covered). Scope: restaurants.
{"as_of":"2026-10-12T04:00:00Z","restaurants":[{"id":"…","name":"Maple Street Pizzeria","status":"covered","time_zone":"America/Chicago","unlocked_features":["menu_engineering","…"]}]}
GET /v1/metrics/daily?from=2026-09-01&to=2026-09-30
One row per covered restaurant per day, all restaurants in one call. Optional restaurant_id (repeatable). At most 400 days per request. Only finished days are served, so the latest row is yesterday. The taste average needs at least 3 visits with a rated dish and the would-return rate at least 3 answers; otherwise they are null. View, share and impression counts are null unless the restaurant has Impressions over time. Scope: metrics.daily.
{"as_of":"…","from":"2026-09-01","to":"2026-09-30","rows":[{"restaurant_id":"…","date":"2026-09-01","visits":14,"avg_taste":4.3,"pct_would_return":85.7,"restaurant_views":120,"dish_detail_views":64,"dish_photo_views":31,"restaurant_shares":2,"dish_shares":1,"dish_photo_shares":0,"impressions":940}]}
GET /v1/restaurants/{id}/menu
Per-dish scorecard and comment counts per dish (counts only, never comment text). Scope: menu.
{"as_of":"…","restaurant_id":"…","time_zone":"…","data":{"scorecard":{"rows":[…]},"comment_counts":[{"dish_key":"margherita","comments":3}]}}
GET /v1/restaurants/{id}/menu/dishes/{name}
One dish by name. Scope: menu.
{"as_of":"…","restaurant_id":"…","data":{"name":"Margherita","ratings":42,"taste":4.4,…}}
GET /v1/restaurants/{id}/insights
Menu engineering, promotion results and quality alerts. Scope: insights.
{"as_of":"…","restaurant_id":"…","data":{"menu_engineering":{…},"roi":{…},"alerts":[…]}}
GET /v1/restaurants/{id}/benchmarks
Tag, category and price comparisons with nearby restaurants. Scope: benchmarks.
{"as_of":"…","restaurant_id":"…","data":{"tag_comparisons":[…],"category_benchmark":{…},"price_check":{…}}}
GET /v1/restaurants/{id}/guests
First and return visits, repeat visitors, origin areas and post reach. Scope: guests.
{"as_of":"…","restaurant_id":"…","data":{"guests":{…},"repeat_visitors":{…},"origins":[…],"reach":{…}}}
GET /v1/restaurants/{id}/questions
Ask your guests questions with answer counts, hidden below 3 answers. Scope: questions.
{"as_of":"…","restaurant_id":"…","data":{"questions":[{"question":"…","options":["Yes","No"],"answers":12,"counts":[9,3]}]}}
GET /v1/locations/comparison
The owner's covered locations side by side. Scope: locations.
{"as_of":"…","data":{"days":30,"rows":[…]}}
Errors
| Status | error | Meaning |
|---|---|---|
| 503 | api_disabled | The Data API isn't open yet. |
| 400 | unsupported_grant_type | Only client_credentials is supported. |
| 401 | invalid_client | Unknown client ID or wrong secret. |
| 401 | invalid_token | Missing, expired or revoked access token. |
| 403 | insufficient_scope | The client doesn't have that scope. |
| 403 | restaurant_not_covered | The restaurant's plan doesn't include the Data API right now. |
| 404 | not_found | No such restaurant on this account, or no dish by that name. |
| 429 | rate_limited | Too many requests. Wait for the number of seconds in Retry-After. |
Limits
Per client: 30 requests a minute plus 5 for each covered restaurant, and 500 requests a day for each covered restaurant (days reset at midnight UTC). A nightly pull per restaurant uses a tiny fraction of that. Detail sections are cached for up to 6 hours and daily figures are rebuilt overnight, so polling more often than that returns the same data. A client that keeps calling far past its limit is paused automatically, and the owner is emailed.
Versioning
Fields in /v1 are only ever added, never removed or changed in meaning. A breaking change means /v2, announced in advance, with /v1 kept running for a while alongside it.
Showing the data publicly
Internal use needs nothing. Anything shown to the public must credit EatOutLog and follow section 6 of the Restaurant Operator Terms. The attribution kit has the logo files and wording to use. Use of the API is covered by section 7.
Testing
Ask us for test credentials on our staging environment (https://api.stage.capypine.com), which serve a demo restaurant with sample data, so you can build before going live. Contact sales@capypine.com.