API v3 New
API v3 is free on Pay-as-you-go and Grow until 31 October 2026. Requests take no credits and count toward no monthly limit; the per-minute rate limit still applies.
API v3 is the data stack that powers agent awareness. Elfa monitors news and market chatter worldwide, across crypto and equities, and turns it into events, positions and rankings, so your agents get the latest real-time context and react faster when the stakes are high.
| Question | Endpoint (GET) | Returns |
|---|---|---|
| Which id is this? | /v3/entities | The id every other endpoint takes, from a ticker, name, handle, address, CoinGecko id, FIGI or CIK |
| What is happening? | /v3/events | Events: what happened, what it names, how prices reacted. Searchable by topic |
/v3/events/storylines | One development followed over days | |
/v3/events/arcs | Storylines grouped into a larger movement | |
| Where is attention? | /v3/market/crypto/mindshare, …/equity/mindshare | Assets ranked by share of attention, with hot |
/v3/market/crypto/trending-contracts | Contract addresses ranked by how many posts pasted them | |
| Which way does the crowd lean? | /v3/market/crypto/call-book, …/equity/call-book | The whole market's long/short lean, hour by hour |
/v3/calls/positioning | Open longs and shorts on one asset, now | |
| What are accounts doing? | /v3/calls | Every post that takes or changes a position |
/v3/calls/episodes | Each position from open to close, with prices and the author's track record | |
| Who is worth reading? | /v3/people/accounts | Accounts ranked by standing, or by their record as callers |
| What can my key do? | /v3/key-status | Plan, credits, limits and how far back it reads |
No endpoint returns post text. Events carry a written title and summary, and link to each post behind them.
To be alerted when a new event matches your filters, rather than polling, use
an Auto events condition. See
Alerts on New Events.
New to the terms? Concepts shows each one with a real example.
Quickstart
Quickstart resolves an entity, reads its events and checks positioning, in cURL, JavaScript and Python.
Rules Every Endpoint Follows
| Rule | In short |
|---|---|
| Authentication | Send x-elfa-api-key on every request |
| Access | PAYG, Grow and Enterprise keys |
| Times | Unix seconds, UTC, in requests and responses. Milliseconds are a 400: divide by 1000 |
| Time ranges | from is required, to defaults to now, both inclusive |
| History | 30 days, 60 days or 2 years back, by plan. An earlier from is cut, and servedFrom says where |
| Paging | Pass nextCursor back as cursor. No offset, no total |
| Lists | Parameters marked a list take several values, repeated or comma-separated. At most 30 ids |
| By id | eventIds, storylineIds, arcIds, callIds and episodeIds fetch up to 30, with no from |
| Errors | A bad parameter, or an unknown id in a filter, is a 400. Nothing matching is a 200 with an empty list |
Authentication, Access and Rate Limits
Authentication, access and rate limits: see Get Started. Which plans can call v3 is under Access; the per-minute limit is under Rate Limits.
Time Ranges
| Parameter | Value |
|---|---|
from | Unix seconds. Required, except when fetching by id or searching |
to | Unix seconds. Defaults to now |
There is no default range: leaving out from is a 400, from is required.
Some endpoints read time their own way:
- Mindshare takes a
periodand an optionalto. - Call episodes match a position open at any point in the range.
- Events with
sort=relevantrank the last 24 hours. - A search with
qstarts at your history by default. - Trending contracts read 30 days at most.
- Entities, arcs, positioning and people take no range:
fromis a400.
History
| Plan | Reads back |
|---|---|
| PAYG | 30 days |
| Grow | 60 days |
| Enterprise | 2 years |
Counted from midnight UTC. /v3/key-status returns the
start as historyFrom.
from before historyFrom -> cut to historyFrom, and servedFrom says so
to before historyFrom -> 400 "This plan answers from 1788307200 onwards."
an id older than it -> skipped when you fetch by id
servedFromis on every list that takesfrom. It isnullwhen you fetch by id withoutfrom, and on events withsort=relevant.- Storylines, arcs, call episodes and mindshare apply the limit as their pages say.
- The limit moves at midnight UTC. A cursor from a range it cut then stops working: start again from the first page.
Paging
{
"events": [ … ],
"nextCursor": "TUHFseJr.MjAy…",
"hasMore": true,
"servedFrom": 1790672305
}
- Pass
nextCursorback ascursor.hasMore: falseandnextCursor: nullmark the last page. There is no offset and no total. - A cursor belongs to its query. Change anything but
limitand it is a400,Invalid cursor…. Start again without it. Treat a cursor as opaque. - The list is named for what it holds:
events,storylines,arcs,entities,bars,assets,contracts,calls,episodes,accounts. orderisdesc(default) orascwhere an endpoint takes it. Entities, mindshare and trending contracts take none.
| Endpoints | Default limit | Most |
|---|---|---|
| Events, storylines, arcs, calls, call episodes | 10 | 30 |
| Call books, mindshare, trending contracts, top accounts | 50 | 200 |
| Entities | 10 | 200 |
Lists of Values
?entityIds=<id1>,<id2>
?entityIds=<id1>&entityIds=<id2>
Only parameters marked a list take several values: eventClass=market,asset
is a 400. A list of ids takes at most 30, and entityIds matches any of
them.
Fetching by Id
eventIds, storylineIds, arcIds, callIds and episodeIds take up to 30
ids you already hold:
- No
from, and no next page: everything found comes back at once. - An id we do not hold, or one older than your history, is skipped, not an error.
- Other filters still apply, except with
eventIds, which combines only withalertAction,orderandsort=latest.
Errors
Every error has the body { code, message, details?, errorId, requestId }
(see Errors).
Branch on code or the status, not on message. The common ones:
| You sent | Answer | Do |
|---|---|---|
No from | 400, from is required | Send from |
| A range wholly before your history | 400, This plan answers from … onwards. | Move to later |
| An unknown parameter | 400, Unrecognized: … in details | Fix or drop it. Unknown parameters are never ignored |
A bad value: an unknown enum, milliseconds, from after to, a malformed id | 400 naming the field in details | Fix that field |
| A cursor from another query | 400, Invalid cursor… | Start again without it |
limit over the most | 400, limit must be 30 or less | Lower it |
| An entity id that is not a UUID | 400, must be an id from /v3/entities | Resolve it with /v3/entities |
| A UUID we do not hold | 400, Unknown id: … | Resolve it again |
| A person, project or organisation where an asset is needed | 400, … is not an asset family. | Resolve with entityType=token or equity |
| A handle we do not hold, on calls or episodes | 400, Unknown handle: … | Check the spelling |
| A filter that matches nothing | 200, an empty list | Widen the range |
q while search is down | 503, Search is unavailable right now… | Retry, or drop q |
Enums and Errors lists every status, and which are worth retrying.