Frequently asked questions
Keys & account
I lost my API key. Can you show it to me again?
We cannot look up an old plaintext key. If you still have any
account:manage key, create a replacement or rotate through the
dashboard. Direct API rotation requires a fresh
32-byte rot_… Idempotency-Key; keep the old key and
nonce until the response is safely stored because that exact pair can recover
an interrupted delivery for 15 minutes.
If every management key is gone, use the secure recovery page. A link can be issued only if the exact current account mailbox was explicitly verified before the final management key was lost. Unknown and unverified addresses receive the same generic accepted response, but an unverified request creates no recovery link. The request is resolved asynchronously through an encrypted blind queue, so allow a few seconds for an eligible verified buyer's 30-minute fragment-only email link. Claiming it revokes all existing keys and issues one full-management replacement; the exact link bearer can recover an interrupted response for 10 minutes. The replacement is shown only on the first-party page and is never emailed. Suspended, canceled, held, unverified, reconciliation-required, or expired-grace accounts require support. Never send us the recovery link itself.
Why do I need to verify the recovery email separately?
Possession of an account email address is not proof that its mailbox owner should be able to recover your account. Separate, explicit verification prevents an unconfirmed address from gaining authority to trigger the all-key replacement flow. Verification itself changes no API key; it only authorizes the exact current mailbox for a possible future recovery.
I did not receive the recovery-email verification message. What now?
While you still have an account:manage key, open the dashboard and
choose Send verification email. Requests are limited to one per customer
every 10 minutes, links are single-use and expire after 24 hours, and the generic
accepted response does not guarantee that a new message was sent. Check the
account mailbox and its spam filtering. If you have already lost every management
key and the mailbox was never verified, contact support; the public recovery form
will deliberately issue nothing.
How many keys can I have?
Up to 5 active keys per account. Create named keys per system (production, staging, research) in the dashboard, and revoke any of them independently.
Which permissions should an application key have?
Use a data:read-only key for pollers, services, and analytics
jobs. It can retrieve odds but cannot inspect your account or create, revoke,
or rotate credentials. Keep a key with account:manage in your
secrets manager for the dashboard and key administration. New dashboard keys
default to data-only.
Quota & billing
How do I update payment details or manage my subscription?
For a paid account, sign in to the buyer dashboard with an
account:manage key and choose Manage billing. This creates a
fresh short-lived Stripe-hosted session for payment details, invoices, and the
configured cancellation flow. The link should not be logged, bookmarked, or
shared. Private beta access has no card, charge, renewal, or paid subscription
to manage. Contact support for access or plan changes.
What exactly does one API call cost?
On ordinary routes, one credit includes up to 20 returned rows; every
additional started 20-row block costs one more credit, and an empty result costs
one credit. Verified live=1 discovery is variable: it charges the
greater of returned-row credits and bounded discovery/offer-check work through
the same 20-unit blocks. Narrow its filters and limit to control that
work. Every metered response reports the authoritative final amount in
X-Credits-Cost. See
Quotas & metering.
What happens when I exhaust my quota?
Calls return 429 quota_exceeded with a Retry-After
header counting down to the first applicable daily or plan-period reset. Your
key is never deleted for overuse — service resumes automatically at reset. A
private-beta limit change or extension requires a separately reviewed and
approved offer; paid plan changes use the documented paid flow. A request that
cannot reserve its certified maximum charge is rejected before data work and
does not consume buyer credits.
Do cached responses cost credits?
Yes — metering is per request/row regardless of cache path (that's what
keeps usage accounting simple and predictable). The benefit of cache is avoiding the
source round trip, not a guaranteed latency or lower credit cost. To spend
fewer credits, poll incrementally with since — see
Polling & performance.
Data & freshness
Where does the odds data come from?
The feed is sourced from Pinnacle. SharpRelay provides the independent delivery layer around it: a stable REST contract, buyer API keys, hard quotas, caching, request tracing, and normalized failures. SharpRelay is not affiliated with, endorsed by, or sponsored by Pinnacle.
How fresh are the odds?
Timeline endpoints (/v1/events/{event_id}/odds, /v1/props/{prop_id}/odds)
bypass the response cache and request the current source view; actual freshness
and availability still depend on source and network conditions. Reference
endpoints are cached briefly (ordinary fixtures and closing/results ~30s,
sports/leagues ~1h, and non-empty opening snapshots up to 24h); outright
discovery is cached for roughly five minutes. Verified live=1
discovery is not response-cached: every request freshly retrieves source
candidates from the complete bounded boundary, then performs bounded per-page
verification. Every returned event has live_status=1; its latest odds
are bound to that event and contain an open line whose cutoff remains strictly
future when expiry is rechecked at final validation. No arbitrary update-age or
kickoff-age rule is imposed. Empty opening, closing, and result responses are
not cached. Closing lines and results can be
corrected or re-settled, so refresh them whenever revisions matter. The
X-Cache header shows which cache path served your response when the
disposable cache is available; an absent header can also mean the route bypassed
cache, caching was disabled, or that cache was unavailable.
Why did event discovery return only future fixtures?
That is the safe default for ordinary GET /v1/events. A present
or future starts_from remains locally enforced as a future lower
bound; only a genuinely past value opts into historical discovery. Pair it with
starts_to to set a locally enforced inclusive timestamp or complete
UTC-day upper bound. An exact event_id or
parent_id lookup targets that identifier's lifecycle directly. Use
live=1 for currently verified in-play offers rather than widening a
historical fixture window. Without an explicit window or identifier, starts
must remain strictly after the request boundary and in the future at final
validation.
Which prop operations are available in the private beta?
The v1 beta publishes 12 authenticated, read-only data routes. Discover event
props through /v1/events/{event_id}/props, then use each returned
special_id as prop_id to request latest or available
historical prices from /v1/props/{prop_id}/odds. Discover outrights
through /v1/outrights and price each returned ID the same way.
Event-wide bulk prop prices and prop-specific opening, closing, results, and CLV
operations are not exposed in the v1 private beta.
What sports and markets are covered?
Coverage follows the currently available source catalog. Call
/v1/catalog/sports for the current list and
/v1/catalog/leagues?sport_id=… for available leagues. Returned
markets can include moneyline, spreads, totals (full match and per-period),
player/team specials, and outrights where available for that sport, event,
source state, and plan. Catalog responses can be served from the disposable
cache for roughly one hour, so inspect X-Cache and refresh on a slow
timer rather than treating the response as zero-staleness.
How much history is available?
Historical depth varies by sport, event, market, and source availability.
Event odds default to every primary and alternate market row at the greatest
positive line_id for each event and period; older off-board line IDs
are excluded. Prop odds default to one greatest-line_id row per
special_id + contestant_line_id, with handicap treated as
a value on that row rather than a separate latest identity. Use
full_history=1 to request available matching history. Event odds
additionally accept a moving since timestamp for incremental history
(budget credits for the row volume). Use since by itself or with
full_history=1; since=...&full_history=0 is rejected.
Always inspect X-Result-Truncated and do not assume a historical
response is complete. Use /v1/events/{event_id}/lines/opening and
/v1/events/{event_id}/lines/closing for available first/last lines.
These options do not guarantee a complete event history.
Troubleshooting
I'm getting 401s with a valid-looking key.
Check for whitespace/newlines when pasting, confirm the key is
active in the dashboard, and make sure you're sending
Authorization: Bearer sr_live_… (not the key ID shown in tables).
If it was recently rotated, the old key is dead by design.
Something looks wrong — how do I report it?
Include the request_id from the error envelope (or the
X-Request-Id header of the suspicious response) and the UTC
time. With those we can trace the exact request end to end.