# Account
Source: https://docs.dripstack.com/account
Who this API key or MCP OAuth token is, plus links to credits and unlocks.
Account routes tell an agent **who it is authenticated as**, **how many
credits remain**, and **which posts it already unlocked**. They do not
return article summaries.
Requires `Authorization: Bearer pk_drip_…` or an MCP OAuth access token with
`mcp:unlock`. Session JWTs are rejected (`401`).
Create a key and add balance from the
[API Keys](https://dripstack.com/connect/api) and
[Billing](https://dripstack.com/billing).
| Need | Route | Guide |
| - | - | - |
| Who is this credential? | `GET /api/v1/me` | this page |
| Credit balance and top-up URL | `GET /api/v1/me/credits` | [Credits](/credits) |
| Credit ledger | `GET /api/v1/me/credits/activity` | [Credits](/credits#ledger) |
| Posts this account already unlocked | `GET /api/v1/me/unlocks` | [Unlocks](/unlocks) |
MCP: `get_account`, `get_credits_balance`, `get_subscription_upgrade_url`,
`list_credit_activity`, `list_unlocked_posts`. Use `unlock_post` to retrieve paid content. Its first
unlock requires `confirmSpend: true`; free re-reads do not.
## Who is this credential?
```bash theme={null}
curl -H "Authorization: Bearer pk_drip_…" "https://dripstack.com/api/v1/me"
```
```json theme={null}
{
"authMethod": "apikey",
"apiKey": { "name": "Default", "suffix": "abcd1234" },
"scopes": null
}
```
OAuth tokens return `authMethod: "oauth"`, `apiKey: null`, and `scopes`
(for example `["mcp:unlock"]`). Never returns raw keys or user ids.
# Auth introspection for the current API key or OAuth token.
Source: https://docs.dripstack.com/api-reference/account/auth-introspection-for-the-current-api-key-or-oauth-token
https://dripstack.com/openapi.json get /api/v1/me
Returns auth method, API key name/suffix (when using `pk_drip_…`), or OAuth scopes (when using `mcp_at_…`). Requires bearer API key or OAuth access token with `mcp:unlock`. Session JWTs are rejected. Never returns raw keys or user ids.
# Available credit balance and top-up URLs.
Source: https://docs.dripstack.com/api-reference/account/available-credit-balance-and-top-up-urls
https://dripstack.com/openapi.json get /api/v1/me/credits
Returns spendable balance across active signup and top-up credit pools plus lifetime purchased/spent totals and `topUpUrl` / `dashboardUrl`. Expired credits are excluded. Lifetime purchased totals include purchases and promos, not signup grants. Requires bearer API key or OAuth access token with `mcp:unlock`. Session JWTs are rejected. There is no top-up API — send users to `topUpUrl`.
# Cursor-paginated credit ledger activity.
Source: https://docs.dripstack.com/api-reference/account/cursor-paginated-credit-ledger-activity
https://dripstack.com/openapi.json get /api/v1/me/credits/activity
Returns credit ledger rows for the authenticated account (newest first). Same item fields as the dashboard history. Requires bearer API key or OAuth access token with `mcp:unlock`. Session JWTs are rejected.
# Cursor-paginated posts unlocked for lifetime access.
Source: https://docs.dripstack.com/api-reference/account/cursor-paginated-posts-unlocked-for-lifetime-access
https://dripstack.com/openapi.json get /api/v1/me/unlocks
Returns posts this account already paid to unlock (newest first). Metadata only — `synthesizedSummary` stays on the paid publication-post route / `unlock_post`. Requires bearer API key or OAuth access token with `mcp:unlock`. Session JWTs are rejected.
# Get one company profile by id.
Source: https://docs.dripstack.com/api-reference/companies/get-one-company-profile-by-id
https://dripstack.com/openapi.json get /api/v1/companies/{companyId}
Returns the same profile object as an item from GET /api/v1/companies. Unknown ids and ids that are not companies return 404.
# Look up a company profile by ticker, domain, qid, CIK, or name.
Source: https://docs.dripstack.com/api-reference/companies/look-up-a-company-profile-by-ticker-domain-qid-cik-or-name
https://dripstack.com/openapi.json get /api/v1/companies
Identity lookup for a company (who is NVDA / nvidia.com?), not article search. Use /api/v1/entities/search after you have a ticker to find articles that mention it. At least one of ticker, domain, qid, cik, or name is required. When more than one is given, lookup uses qid, then ticker, then domain, then cik, then name to find candidates; the remaining identifiers must also match (AND). Empty matches return 200 with items: []. Unexpected lookup failures return 500.
# Daily market brief for one date (paid).
Source: https://docs.dripstack.com/api-reference/daily-brief/daily-market-brief-for-one-date-paid
https://dripstack.com/openapi.json get /api/v1/daily-brief/{date}
Returns the daily market brief as markdown for a single UTC calendar date. Same unified payment flow as paid posts — pay via x402/MPP (402 challenge) or spend Drip credits with a bearer API key / OAuth token. The first paid read caches the brief for the paying subject (wallet, payment credential, or Drip user); later reads of the same date return it for free with no `paymentInfo`. There is no unlock token — free re-reads are keyed by the paying subject, so authenticate or pay from the same wallet to re-read.
# Get one podcast with recent episodes.
Source: https://docs.dripstack.com/api-reference/podcasts/get-one-podcast-with-recent-episodes
https://dripstack.com/openapi.json get /api/v1/podcasts/{publicationSlug}
# List curated podcasts.
Source: https://docs.dripstack.com/api-reference/podcasts/list-curated-podcasts
https://dripstack.com/openapi.json get /api/v1/podcasts
# Access post with credits (paid, same as GET).
Source: https://docs.dripstack.com/api-reference/posts/access-post-with-credits-paid-same-as-get
https://dripstack.com/openapi.json post /api/v1/publications/{publicationSlug}/{postSlug}
Same unified payment flow as GET — first pay unlocks forever for that subject; later fetches are free. Unauthenticated requests receive a 402 x402/MPP challenge. Authenticated requests (JWT or API key) pay via your credit balance on first unlock.
# Get article summaries or podcast transcripts (paid).
Source: https://docs.dripstack.com/api-reference/posts/get-article-summaries-or-podcast-transcripts-paid
https://dripstack.com/openapi.json get /api/v1/publications/{publicationSlug}/{postSlug}
Returns post metadata and synthesized summary after payment. Podcast episodes may include a transcript. The first successful pay unlocks that post forever for the paying subject (Drip user for credits/API key/JWT/MCP OAuth; wallet or MPP credential otherwise). Later fetches are free. x402/MPP clients should store `unlockToken` / `X-Drip-Unlock` from the first settle and send `X-Drip-Unlock` on free re-reads.
# List the most purchased posts.
Source: https://docs.dripstack.com/api-reference/posts/list-the-most-purchased-posts
https://dripstack.com/openapi.json get /api/v1/posts/top-selling
# Get one publication with recent posts.
Source: https://docs.dripstack.com/api-reference/publications/get-one-publication-with-recent-posts
https://dripstack.com/openapi.json get /api/v1/publications/{publicationSlug}
# List curated newsletters, podcasts, and publications.
Source: https://docs.dripstack.com/api-reference/publications/list-curated-newsletters-podcasts-and-publications
https://dripstack.com/openapi.json get /api/v1/publications
# List the highest-earning publications.
Source: https://docs.dripstack.com/api-reference/publications/list-the-highest-earning-publications
https://dripstack.com/openapi.json get /api/v1/publications/top-selling
# Search curated publications, newsletters, podcasts, and authors.
Source: https://docs.dripstack.com/api-reference/publications/search-curated-publications-newsletters-podcasts-and-authors
https://dripstack.com/openapi.json get /api/v1/publications/search
# Find articles that mention an entity or are linked to a stock pick.
Source: https://docs.dripstack.com/api-reference/search/find-articles-that-mention-an-entity-or-are-linked-to-a-stock-pick
https://dripstack.com/openapi.json get /api/v1/entities/search
Free article discovery sorted by publication date (latest first by default) — use this to answer "what did analysts say about X this week?" rather than /api/v1/search's topic-relevance ranking. Set stockPicksOnly=true to restrict results to source posts linked to stock-pick rows. With stockPicksOnly=true and ticker, ticker matching is exact against StockPickCall.ticker and bypasses ticker metadata expansion. author matches the canonical source article/pick author. sort=earliest returns the oldest matching article first. Limited to curated, non-disabled publications.
# Search premium financial newsletter and podcast posts by topic.
Source: https://docs.dripstack.com/api-reference/search/search-premium-financial-newsletter-and-podcast-posts-by-topic
https://dripstack.com/openapi.json get /api/v1/search
# V1 — List stock-picker calls for one day (paid, legacy).
Source: https://docs.dripstack.com/api-reference/stock-picks/v1-—-list-stock-picker-calls-for-one-day-paid-legacy
https://dripstack.com/openapi.json get /api/v1/stock-picks
V1 (legacy — still available; prefer V2 `/api/v2/stock-picks` for new integrations). Returns structured stock-picker calls for AI-agent consumption. Covers one UTC effective calendar day, not a range. Defaults to the latest day with picks when `date` is omitted. Use `date=YYYY-MM-DD` for a specific day. Rows without `publishedAt` may use extraction time internally. Call the free quote route first to learn `amountUsd`. Returns 404 when no picks exist for the resolved day — do not pay on 404.
# V1 — Quote the stock-picks bundle price for one day (free, legacy).
Source: https://docs.dripstack.com/api-reference/stock-picks/v1-—-quote-the-stock-picks-bundle-price-for-one-day-free-legacy
https://dripstack.com/openapi.json get /api/v1/stock-picks/quote
V1 (legacy — still available; prefer V2). Free preflight for the paid stock-picks route. Returns the exact bundle `amountUsd` and per-attributed-post breakdown for the same `date`/`limit` the paid route would charge. Does not return pick rows, tickers, or evidence. Use this before confirming spend, then call `GET /api/v1/stock-picks` (or MCP `list_stock_picks`) with the frozen `dateUsed`. Live `402` on the paid route remains authoritative for payment clients.
# V2 — Quote the stock-picks bundle price for one day (free).
Source: https://docs.dripstack.com/api-reference/stock-picks/v2-—-quote-the-stock-picks-bundle-price-for-one-day-free
https://dripstack.com/openapi.json get /api/v2/stock-picks/quote
V2 (recommended over V1). Free preflight identical to V1: same price logic and response shape for the same `date`/`limit`. Returns the exact bundle `amountUsd` the paid flow would charge. No auth required.
# V2 — Stock picks with subscription access, credits, or x402 pay-per-use.
Source: https://docs.dripstack.com/api-reference/stock-picks/v2-—-stock-picks-with-subscription-access-credits-or-x402-pay-per-use
https://dripstack.com/openapi.json get /api/v2/stock-picks
V2 (recommended over V1). Tier-aware stock-picks API. Bearer API key / JWT / OAuth resolves the subscription first: EXPERT sees full history, PRO is clamped to the live 7-day window, and neither is ever charged for requests their plan covers. Anonymous callers use x402; authenticated callers without a paid plan spend Drip credits. Each paid request buys one dated bundle, priced at the flat unit × distinct attributed source articles. Filters, search, range pagination, and prices apply to subscription reads; the paid flow uses `date`/`limit` and `sort`, and ignores the subscription-only options. Out-of-window explicit `date` returns 403; PRO ranges are clamped, with 403 when there is no overlap (see `meta.appliedRange`).
# Company Lookup
Source: https://docs.dripstack.com/companies
Look up a company identity card by ticker, domain, qid, CIK, or name.
Use `GET /api/v1/companies` when the question is **who is this company?**
(NVDA, nvidia.com, a CIK, or a name). This is not article search — after you
have a ticker, use [Entity Search](/entity-search/ticker) for mentioning
articles.
Free, no auth required. Empty matches return `200` with `items: []`.
Unexpected lookup failures return `500`.
## List
At least one of `ticker`, `domain`, `qid`, `cik`, or `name` is required.
When more than one is given, lookup uses **qid > ticker > domain > cik >
name** to find candidates; the remaining identifiers must also match.
```bash theme={null}
curl "https://dripstack.com/api/v1/companies?ticker=NVDA"
curl "https://dripstack.com/api/v1/companies?domain=nvidia.com"
```
| Parameter | Required | Description |
| - | - | - |
| `ticker` | one of | Stock ticker, 1-8 characters (letters/numbers/`.`/`-`) |
| `domain` | one of | Official website host, e.g. `nvidia.com` |
| `qid` | one of | Company id, e.g. `Q182477` |
| `cik` | one of | SEC CIK, 1-10 digits |
| `name` | one of | Company name, minimum 2 characters, when no other identifier is known |
| `limit` | optional | 1-10, defaults to 5 |
## Response
```json theme={null}
{
"query": {
"ticker": "NVDA",
"domain": null,
"qid": null,
"cik": null,
"name": null
},
"count": 1,
"items": [
{
"id": "Q182477",
"name": "NVIDIA",
"description": "American technology company",
"identifiers": {
"ticker": "NVDA",
"domain": "nvidia.com",
"cik": "0001045810",
"qid": "Q182477"
}
}
]
}
```
Present `name` plus `identifiers.ticker` / `domain` to users — do not lead
with raw ids.
## One company
`GET /api/v1/companies/{companyId}` returns the same profile object as a list
item. Use the `id` from the list route. Unknown ids and ids that are not
companies return `404`.
```bash theme={null}
curl "https://dripstack.com/api/v1/companies/Q182477"
```
# Core Concepts
Source: https://docs.dripstack.com/concepts/core-concepts
Key ideas in the Drip API: publications, posts, search, and paid article summaries.
Drip is organized around a few simple API concepts. Search across supported
financial newsletters, blogs, and podcasts, choose a relevant post, then unlock the paid
summary when your agent needs it for research.
## Publication
A **publication** is a supported source, such as a newsletter, blog, or podcast.
It is identified by a **`publicationSlug`**, typically a normalized hostname.
| Source URL | `publicationSlug` |
| - | - |
| `https://michaeljburry.substack.com` | `michaeljburry.substack.com` |
| `https://unchainedcrypto.beehiiv.com` | `unchainedcrypto.beehiiv.com` |
Use `GET /api/v1/publications` to list the curated catalog, or
`GET /api/v1/publications/search?q=...` to find a source by name. Details:
[Publications](/publications).
## Post
A **post** is an article or podcast episode from a publication. It is addressed by its
publication plus its own **`slug`**:
```text theme={null}
GET /api/v1/publications/{publicationSlug}/{postSlug}
```
Search results include both `publicationSlug` and `slug`, so an agent can build
the paid article URL directly from a search result.
## Search
**Search** (`GET /api/v1/search`) is the free discovery layer. Use it to find
candidate posts by topic across supported sources.
The response includes:
| Field | Meaning |
| - | - |
| `items` | Ranked post candidates with fields such as `publicationSlug`, `slug`, `title`, and date |
| `mode` | Search strategy used: `hybrid` combines semantic and keyword search; `fts` is keyword-only |
| `matchConfidence` | Overall result quality: `strong`, `weak`, or `none` |
| `count` | Number of items returned after applying the requested `limit` |
Each item also includes the effective `priceCents` for the post.
Treat `items` as candidates. Fetch the selected post from the paid article
endpoint to receive its robust summary. Parameters, filters, and a full
example: [Topic Search](/search).
## Company lookup
`GET /api/v1/companies` returns an identity card (`name`, ticker, domain, CIK)
for "who is NVDA?" — not articles that mention the company. See
[Company Lookup](/companies).
## Entity search
`GET /api/v1/entities/search` lists curated articles that mention a ticker,
company, person, organization, or subject, sorted by publish date. Start with
[Search Articles by Ticker](/entity-search/ticker). The response includes
`matchedEntity`.
## Top-selling
`GET /api/v1/posts/top-selling` and `GET /api/v1/publications/top-selling`
are free ranked lists for popular items. See [Top-selling](/top-selling).
## Paid Article Summaries
A paid post request returns metadata and a robust `synthesizedSummary`.
Podcast episodes also return `transcript` when available; other posts return
`transcript: null`.
Newsletter and blog responses do not include full article text. The
first successful pay unlocks that post forever for the paying subject (Drip user
for credits / MCP OAuth / API key / JWT; wallet or MPP credential for those
rails). Later fetches return the live summary with no charge and no new sale.
Payment clients use x402 on Base or Solana, or MPP on Tempo or Stripe. An unpaid
request returns a `402` challenge containing the authoritative runtime price.
API-key requests spend account credits instead. x402/MPP clients should
store `unlockToken` (or the `X-Drip-Unlock` response header) and resend it as
the request header `X-Drip-Unlock` for free re-reads.
This lifetime unlock applies to individual posts. Paid stock-picks bundles are
charged per request and do not unlock their source posts. Stock Picks V2 also
supports subscription access; see [Stock Picks](/stock-picks).
# Errors & Retries
Source: https://docs.dripstack.com/concepts/errors-retries
Handle Drip API errors without losing research context or creating unintended charges.
Handle responses according to the resource and payment method. Free discovery
requests can use ordinary retry policies. Individual posts have lifetime
unlocks; paid stock-picks bundles are charged per request.
## Paid summary retry matrix
| Status | Meaning | Charged? | Recommended action |
| - | - | - | - |
| `200` | Summary returned | First unlock only | Store the response and any `unlockToken`; existing unlocks are free |
| `400` | Invalid query or parameters | No | Fix the request; do not retry unchanged |
| `401` | Invalid API key, OAuth token, or payment credential | No | Replace or verify the credential |
| `402` | Payment required | No | Inspect the price, then retry once through a payment-aware client |
| `403` | Insufficient credits or access denied | No | Inspect `reason` / `hint`; add credits or correct access |
| `404` | Publication, post, or curated result not found | No | Verify identifiers or choose another result |
| `500` | Unexpected server error | Depends on request stage | If payment was submitted, verify settlement before retrying |
| `502` | Payment verification or settlement failed | Potentially unknown | Check the wallet or receipt before retrying |
| `503` | Article summary is not ready | No | Retry later; no payment challenge is issued |
Successful free search and publication-discovery requests also return `200`,
but they are not charged. A free post re-read returns `unlocked: true` and
`paymentInfo: { "protocol": "unlock", "amountUsd": "0.00", ... }`.
Do not blindly retry wallet payments or paid stock-picks bundles. A timeout or lost response does
not prove that no charge occurred. Use an existing post unlock when retrying a summary request.
## Error bodies
Drip's JSON errors include `error` (message), `code`, and `hint`. Validation
errors can also include `issues`; credit errors can include `reason`.
Payment-protocol challenges and failures may use the x402 or MPP response
format instead, so inspect the HTTP status and payment headers as well.
Invalid search parameters return `400` with field-level details:
```json theme={null}
{
"error": "Invalid search query.",
"code": "bad_request",
"hint": "Check request parameters against /openapi.json.",
"issues": {
"formErrors": [],
"fieldErrors": {
"q": ["Query must be at least 2 characters."]
}
}
}
```
An invalid API key returns `401`:
```json theme={null}
{
"error": "Unauthorized: API key not found. Create one at /connect/api or reconnect via mcp login.",
"code": "unauthorized",
"hint": "Send Authorization: Bearer pk_drip_… or an OAuth access token (mcp_at_…). See /llms.txt."
}
```
Insufficient API-key credits return `403`:
```json theme={null}
{
"error": "You're out of credits. Top up your balance to continue.",
"code": "forbidden",
"hint": "See /openapi.json for access requirements.",
"reason": "insufficient_credits"
}
```
A missing post returns `404`:
```json theme={null}
{
"error": "Post not found.",
"code": "not_found",
"hint": "See /openapi.json or /llms.txt for available routes."
}
```
A summary that is still processing returns `503`:
```json theme={null}
{
"error": "Post summary is not ready yet.",
"code": "summary_not_ready",
"hint": "Retry later; the summary is still being generated."
}
```
## Safe retry patterns
### Free discovery requests
For `GET /api/v1/search` and publication discovery routes, retry transient `500`
responses with exponential backoff and jitter. Do not retry `400` or `404`
responses without changing the request.
### Summary not ready
For `503 summary_not_ready`, wait before retrying. The response does not include
a payment challenge, so no payment was attempted.
```typescript theme={null}
if (response.status === 503) {
const error = await response.json();
if (error.code === "summary_not_ready") {
// Schedule a later attempt instead of retrying in a tight loop.
return;
}
}
```
### Wallet payments
The normal wallet flow contains exactly one expected retry:
1. Send a plain request and receive `402`.
2. Inspect and approve the challenge.
3. Retry through the x402 or MPP-aware client.
4. Store the successful response and its `unlockToken` / `X-Drip-Unlock` header.
If step 3 times out or returns `502`, inspect the wallet transaction or MPP
receipt before making another paid request. For later reads of the same post,
send `X-Drip-Unlock` with ordinary `fetch`. A valid token returns the current
summary without charging. Treat a new `402` as a new payment decision.
### API-key payments
An API-key post request checks for an existing user unlock before debiting
credits. The first unlock and its debit are recorded together; retries for the
same post and Drip account do not debit again. After a timeout, check
[unlocks](/unlocks) and [credit activity](/credits#ledger) to determine whether
the first request completed, then re-read using the same account.
A `401` or an insufficient-credit `403` is safe to correct and retry. This
post-unlock behavior does not apply to paid stock-picks bundles: each paid
request can debit credits again. Stock Picks V2 subscription requests are
covered by the plan and may return `429` when the API key reaches its allowance.
## Preserve partial research
When an agent purchases several summaries, keep every successful response even
if another request fails. Synthesize only from successful results, identify the
sources that could not be retrieved, and retry failed paid requests only after
confirming their settlement state.
# Payment Flow
Source: https://docs.dripstack.com/concepts/payment-flow
Wallet payment challenges, API-key credits, headers, and pricing semantics.
Paid article-summary routes support two payment models:
* **Payment-aware clients** use x402 with USDC on Base or Solana, or MPP on
Tempo or Stripe (card / Link).
A plain request returns HTTP `402`, then the client retries with payment
credentials.
* **API-key clients** authenticate with
[`Authorization: Bearer pk_drip_...`](/quickstart-api-keys) and spend
account credits. API keys do not use the 402 wallet handshake.
Each first successful paid fetch of a post summary unlocks that post forever for
the paying subject. Later fetches of the same post return the live summary with
no charge and no new sale. Credits / API key / JWT / MCP OAuth share the same
Drip-user entitlement (including in-app chat paid fetches). x402 and MPP clients
should store `X-Drip-Unlock` / `unlockToken` from the first settle and send it
on free re-reads. If the token is lost but the same wallet (x402) or validated
MPP credential is presented again, the server detects the existing unlock, skips
the charge, and re-issues a token.
### Response fields
| Situation | `paymentInfo.protocol` | `amountUsd` | `unlocked` | `unlockToken` / `X-Drip-Unlock` |
| - | - | - | - | - |
| First x402 / MPP pay | `x402` / `mpp` | charged price | omitted | issued |
| Free re-read via `X-Drip-Unlock` | `unlock` | `"0.00"` | `true` | omitted (client already has it) |
| Free re-read via same wallet / validated MPP (lost token) | `unlock` | `"0.00"` | `true` | re-issued |
| First credits pay | `mpp` or `credits` | charged price | omitted | never |
| Credits free re-read | `unlock` | `"0.00"` | `true` | never |
A first API-key post response can report `protocol: "mpp"` when Drip completes
the credit-funded payment through MPP, or `"credits"` otherwise. The request
still spends the authenticated user's credits. Use the credit ledger to inspect
the debit; `spendSource` is not a response field.
Lifetime unlocks apply only to individual posts. Paid stock-picks bundles are
charged on each request and do not grant access to their source posts. Stock
Picks V2 also offers subscription access; see [Stock Picks](/stock-picks).
Invalid or revoked `X-Drip-Unlock` does not block payment: when a pay credential
is also present, the request falls through to that rail (or to a `402` challenge
if none).
## The 402 handshake for wallet clients
1. A plain request to a paid route returns `402` with two headers:
* `WWW-Authenticate: Payment ...` — the MPP challenges for Tempo and Stripe
* `PAYMENT-REQUIRED` — the x402 v2 challenge
2. Retry the **same request** through a payment-aware client, or manually with:
* `Authorization: Payment ` for MPP, or
* a `PAYMENT-SIGNATURE` header for x402 v2.
3. On success (`200`), the response includes `synthesizedSummary` and
`paymentInfo`.
The `402` response lets a wallet-aware client inspect the exact runtime price
before authorizing payment. For discovery-time estimates, publication post
listings include `priceCents`. The runtime challenge is authoritative.
Treat a `402` as a "pay and retry" signal, not a failure. If a plain HTTP request returns `402`,
retry it through the payment-aware client rather than surfacing an error.
A plain request returns a challenge rather than the paid summary:
```http theme={null}
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED:
WWW-Authenticate: Payment
```
After a successful payment, the response identifies how the request was paid:
```json theme={null}
{
"publicationSlug": "fabricatedknowledge.com",
"slug": "ais-600b-question",
"title": "AI's $600B Question",
"synthesizedSummary": "The article examines whether projected AI revenue can justify rapidly expanding infrastructure spending...",
"paymentInfo": {
"amountUsd": "0.50",
"protocol": "x402"
}
}
```
## API-key credits
API keys are traditional bearer tokens created from the
[API keys page](https://dripstack.com/connect/api). Use them
when your agent or backend service should spend an account balance instead of
holding a wallet.
```bash theme={null}
curl \
"https://dripstack.com/api/v1/publications/fabricatedknowledge.com/ais-600b-question" \
-H "Authorization: Bearer $DRIP_API_KEY"
```
API keys spend available account credits, using signup credits before top-ups
for signed-in accounts. If the balance is too low, the paid route
returns `403` with `reason: "insufficient_credits"` instead of issuing a 402
payment challenge. See the [API-key quickstart](/quickstart-api-keys) for the
full setup and request examples.
## Inspect pricing before payment
List a publication's recent posts to compare prices before selecting one:
```bash theme={null}
curl "https://dripstack.com/api/v1/publications/fabricatedknowledge.com?limit=5"
```
```json theme={null}
{
"posts": [
{
"slug": "ais-600b-question",
"title": "AI's $600B Question",
"publishedAt": "2026-06-14T12:00:00.000Z",
"priceCents": 50
}
]
}
```
`priceCents` is useful for selection and agent spending limits. When requesting
the paid route with a wallet, inspect the returned `402` challenge before
authorizing payment because it contains the live price.
## Discovery pricing vs runtime pricing
The OpenAPI discovery document exposes `x-payment-info.offers[]` on paid routes.
These offers are **advisory** — they may list Base or Solana USDC (x402), Tempo,
and Stripe charges, or catalog floor prices.
The **runtime `402` challenge is authoritative**. Per-post pricing comes from
the live challenge, and the price may scale with content — for example,
stock-picks charge a flat unit price times the number of distinct attributed
source articles in the response. Always trust the live `402` over publication
listings or discovery offers.
## Status codes
| Status | Meaning | Action |
| - | - | - |
| `200` | Summary returned; charged on first unlock | Read `synthesizedSummary` |
| `402` | Payment required | Retry the same request through a payment-aware client |
| `403` | Insufficient account credits (API keys) | Top up the credit balance |
| `404` | Content not found | Do not pay; verify the publication / post slugs |
| `503` | Summary not ready (`summary_not_ready`) | Retry later; no payment challenge is issued |
A `404` and a `503` never carry a payment challenge — do not pay on either. `503` means the
summary is still being generated; retry shortly.
For production handling, see [Errors & Retries](/concepts/errors-retries).
## Discovery
Prefer `GET /openapi.json` (OpenAPI 3.1) for route shapes, JSON schemas, and
paid-route `x-payment-info.offers[]` metadata. If OpenAPI is unavailable, use
`GET /.well-known/x402` for the paid resource list in `METHOD /path` form. The
root `x-discovery.ownershipProofs` field is a Drip vendor extension, not part of
core MPP discovery.
# Credits
Source: https://docs.dripstack.com/credits
Available credit balance, top-up URL, and cursor-paginated ledger activity.
Credit routes tell an agent **how much balance remains** and **what moved
that balance**. They do not unlock articles and there is no top-up API —
send users to `topUpUrl`.
Requires `Authorization: Bearer pk_drip_…` or an MCP OAuth access token with
`mcp:unlock`. Session JWTs are rejected (`401`).
MCP: `get_credits_balance`, `list_credit_activity`.
Create a key and add balance from the
[API Keys](https://dripstack.com/connect/api) and
[Billing](https://dripstack.com/billing).
## Balance
```bash theme={null}
curl -H "Authorization: Bearer pk_drip_…" "https://dripstack.com/api/v1/me/credits"
```
```json theme={null}
{
"purchasedBalanceUsd": 4.25,
"lifetimePurchasedUsd": 20,
"lifetimeSpentUsd": 15.75,
"topUpUrl": "https://dripstack.com/pricing",
"dashboardUrl": "https://dripstack.com/billing"
}
```
`purchasedBalanceUsd` is the total spendable balance across active credit pools,
including signup credits and top-ups; expired credits are excluded. For signed-in
accounts, paid reads spend signup credits first, then top-up credits.
`lifetimePurchasedUsd` is purchases and promos only — it excludes signup
grants. Call this before a paid unlock when the balance may be low. On
`403` insufficient credits, send the user to `topUpUrl` and stop.
## Ledger
```bash theme={null}
curl -H "Authorization: Bearer pk_drip_…" \
"https://dripstack.com/api/v1/me/credits/activity?limit=20"
```
Cursor-paginated, newest first. Optional `limit` (1-50, default 20) and
`cursor` (pass the previous `nextCursor`). `nextCursor` is `null` when
exhausted. A bad `limit` returns `400` with field `issues`; an unknown
`cursor` returns `400` with `error: "Invalid cursor."`. Both include
`code: "bad_request"` and `hint`. See [Errors & Retries](/concepts/errors-retries).
```json theme={null}
{
"items": [
{
"id": "ctxn_01",
"kind": "SPEND",
"amountUsd": -0.5,
"balanceAfterUsd": 4.25,
"feature": "api-post-access",
"description": null,
"packageId": null,
"promoCode": null,
"createdAt": "2026-06-15T10:30:00.000Z"
}
],
"nextCursor": null
}
```
`kind` is one of `PURCHASE`, `SPEND`, `REFUND`, `ADJUSTMENT`, `PROMO`,
`REFERRAL`, `SIGNUP`. `amountUsd` is the signed delta. `feature` is set on
spend rows.
See [Account](/account) for who the credential is, and [Unlocks](/unlocks)
for posts this balance already paid for.
# Curated Endpoints
Source: https://docs.dripstack.com/curated-endpoints
Curated endpoints built on top of Drip's indexed financial publications.
These endpoints help discover popular posts and publications in Drip's indexed
financial writing. Top-selling responses contain free discovery cards; selected
posts still require a separate unlock for their summaries.
## Top-selling
Free, no auth. Use these only when the user asks for popular or top-selling
items — not as a substitute for topic or entity search. Full response
shapes: [Top-selling](/top-selling).
### Posts
`GET /api/v1/posts/top-selling` lists the most purchased posts as free post
cards (`publicationSlug`, `slug`, `title`, `priceCents`, `purchaseCount`,
…). Unlock the summary via the paid publication-post route.
```bash theme={null}
curl "https://dripstack.com/api/v1/posts/top-selling?limit=10"
```
### Publications
`GET /api/v1/publications/top-selling` lists the highest-earning publications,
ranked by creator earnings.
```bash theme={null}
curl "https://dripstack.com/api/v1/publications/top-selling?limit=10"
```
`limit` is 1-100 on both routes (default 10).
Stock-picker calls, analyst recommendations, and long/short ideas have their
own guide: [Stock Picks](/stock-picks).
# Search Articles by Company
Source: https://docs.dripstack.com/entity-search/company
Find newsletter and podcast articles that mention a specific company.
Use `GET /api/v1/entities/search` with a `company` to find curated articles
that mention a company by name — a case-insensitive substring match, so
`company=apple` matches "Apple Inc." When a company listing is known, the
name also expands to related tickers, so tagged `$AAPL` posts are included.
Limited to enabled publications curated for chat. Free, no auth required.
## Request
The endpoint requires at least one of `ticker`, `company`, `person`,
`organization`, `subject`, or `author`. Multiple entity inputs are matched
as alternatives; `author` and the other filters narrow the results.
```bash theme={null}
curl "https://dripstack.com/api/v1/entities/search?company=apple&limit=5"
```
| Parameter | Required | Description |
| - | - | - |
| `company` | one of | Company name, minimum 2 characters, matched as a case-insensitive substring |
| `author` | one of | Source article author, minimum 2 characters, matched as a case-insensitive substring |
| `stockPicksOnly` | optional | `true` or `false` (default); only return articles linked to a stock pick when true |
| `sort` | optional | `latest` (default) or `earliest`, ordered by publication date |
| `publicationSlug` | optional | Restrict results to one publication |
| `publishedAfter` / `publishedBefore` | optional | `YYYY-MM-DD`, inclusive UTC calendar day bounds |
| `limit` | optional | 1-30, defaults to 10 |
| `cursor` | optional | Pass the previous response's `nextCursor` to fetch the next page |
Set `sort=earliest` for oldest first. Keep the same filters and sort when
following `nextCursor`. Invalid parameters, reversed date bounds, or an invalid
cursor return `400`.
## Response
```json theme={null}
{
"query": {
"ticker": null,
"company": "apple",
"person": null,
"organization": null,
"subject": null,
"author": null,
"stockPicksOnly": false,
"sort": "latest",
"publicationSlug": null,
"publishedAfter": null,
"publishedBefore": null
},
"matchedEntity": {
"kind": "company",
"name": "Apple",
"description": "American multinational technology company",
"companies": [{ "name": "Apple", "ticker": "AAPL" }],
"tickers": ["AAPL"],
"matchedVia": ["ticker", "company"]
},
"count": 1,
"nextCursor": null,
"items": [
{
"publicationSlug": "stratechery",
"slug": "aapl-earnings-recap",
"title": "Apple's Earnings Recap",
"author": "Ben Thompson",
"publishedAt": "2026-08-15T00:00:00.000Z",
"priceCents": 500,
"url": "https://stratechery.com/p/aapl-earnings-recap",
"isPodcast": false
}
]
}
```
Results are sorted by `publishedAt`, most recent first by default (`sort=latest`).
For relevance ranking, use `/api/v1/search`. `priceCents` is the price to unlock the paid post response;
the search itself is free. `isPodcast` is true for podcast episodes — the
paid post response then includes a `transcript` when ready.
## Company matching
`company` matches against the free-text company names Drip's extraction
pipeline wrote for each article, then ORs in related tickers when known.
`matchedEntity` is `null` when that expansion
misses; the raw company string is still searched. If you already know the
ticker, [Search by Ticker](/entity-search/ticker) is the direct path.
# Search Articles by Organization
Source: https://docs.dripstack.com/entity-search/organization
Find newsletter and podcast articles that mention an organization.
Use `GET /api/v1/entities/search` with an `organization` to find curated
articles that mention an institution (Fed, SEC, OpenAI). The name is matched
against company and theme tags, and may expand to related companies and
tickers. Limited to enabled publications curated for chat. Free, no auth required.
## Request
The endpoint requires at least one of `ticker`, `company`, `person`,
`organization`, `subject`, or `author`. Multiple entity inputs are matched
as alternatives; `author` and the other filters narrow the results.
```bash theme={null}
curl "https://dripstack.com/api/v1/entities/search?organization=Federal%20Reserve&limit=5"
```
| Parameter | Required | Description |
| - | - | - |
| `organization` | one of | Organization name, minimum 2 characters |
| `author` | one of | Source article author, minimum 2 characters, matched as a case-insensitive substring |
| `stockPicksOnly` | optional | `true` or `false` (default); only return articles linked to a stock pick when true |
| `sort` | optional | `latest` (default) or `earliest`, ordered by publication date |
| `publicationSlug` | optional | Restrict results to one publication |
| `publishedAfter` / `publishedBefore` | optional | `YYYY-MM-DD`, inclusive UTC calendar day bounds |
| `limit` | optional | 1-30, defaults to 10 |
| `cursor` | optional | Pass the previous response's `nextCursor` to fetch the next page |
Set `sort=earliest` for oldest first. Keep the same filters and sort when
following `nextCursor`. Invalid parameters, reversed date bounds, or an invalid
cursor return `400`.
## Response
```json theme={null}
{
"query": {
"ticker": null,
"company": null,
"person": null,
"organization": "Federal Reserve",
"subject": null,
"author": null,
"stockPicksOnly": false,
"sort": "latest",
"publicationSlug": null,
"publishedAfter": null,
"publishedBefore": null
},
"matchedEntity": {
"kind": "organization",
"name": "Federal Reserve",
"description": "central banking system of the United States",
"companies": [],
"tickers": [],
"matchedVia": ["company", "theme"]
},
"count": 1,
"nextCursor": null,
"items": [
{
"publicationSlug": "stratechery",
"slug": "fed-rate-decision",
"title": "The Fed's Rate Decision",
"author": "Ben Thompson",
"publishedAt": "2026-07-30T00:00:00.000Z",
"priceCents": 500,
"url": "https://stratechery.com/p/fed-rate-decision",
"isPodcast": false
}
]
}
```
Results are sorted by `publishedAt`, most recent first by default (`sort=latest`).
Broad thematic research still belongs on topic search; use `organization` when you want
recency-ranked articles that mention a named institution.
# Search Articles by Person
Source: https://docs.dripstack.com/entity-search/person
Find newsletter and podcast articles that mention a person.
Use `GET /api/v1/entities/search` with a `person` to find curated articles
that mention someone by name. Person queries expand to related employers and
tickers when known, then match tagged `persons` on post metadata plus related
companies/tickers and the person's name in titles. Limited to enabled
publications curated for chat. Free, no auth required.
## Request
The endpoint requires at least one of `ticker`, `company`, `person`,
`organization`, `subject`, or `author`. Multiple entity inputs are matched
as alternatives; `author` and the other filters narrow the results.
```bash theme={null}
curl "https://dripstack.com/api/v1/entities/search?person=Warren%20Buffett&limit=5"
```
| Parameter | Required | Description |
| - | - | - |
| `person` | one of | Person name, minimum 2 characters |
| `author` | one of | Source article author, minimum 2 characters, matched as a case-insensitive substring |
| `stockPicksOnly` | optional | `true` or `false` (default); only return articles linked to a stock pick when true |
| `sort` | optional | `latest` (default) or `earliest`, ordered by publication date |
| `publicationSlug` | optional | Restrict results to one publication |
| `publishedAfter` / `publishedBefore` | optional | `YYYY-MM-DD`, inclusive UTC calendar day bounds |
| `limit` | optional | 1-30, defaults to 10 |
| `cursor` | optional | Pass the previous response's `nextCursor` to fetch the next page |
Set `sort=earliest` for oldest first. Keep the same filters and sort when
following `nextCursor`. Invalid parameters, reversed date bounds, or an invalid
cursor return `400`.
## Response
```json theme={null}
{
"query": {
"ticker": null,
"company": null,
"person": "Warren Buffett",
"organization": null,
"subject": null,
"author": null,
"stockPicksOnly": false,
"sort": "latest",
"publicationSlug": null,
"publishedAfter": null,
"publishedBefore": null
},
"matchedEntity": {
"kind": "person",
"name": "Warren Buffett",
"description": "American investor",
"companies": [{ "name": "Berkshire Hathaway", "ticker": "BRK.B" }],
"tickers": ["BRK.B"],
"matchedVia": ["ticker", "company", "person", "title"]
},
"count": 1,
"nextCursor": null,
"items": [
{
"publicationSlug": "stratechery",
"slug": "buffett-letter",
"title": "Warren Buffett's Annual Letter",
"author": "Ben Thompson",
"publishedAt": "2026-02-22T00:00:00.000Z",
"priceCents": 500,
"url": "https://stratechery.com/p/buffett-letter",
"isPodcast": false
}
]
}
```
Results are sorted by `publishedAt`, most recent first by default (`sort=latest`).
`matchedEntity` is the person card used for search. It is `null` when expansion misses; the
raw person string is still matched against tagged `persons` and titles in
that case.
# Search Articles by Subject
Source: https://docs.dripstack.com/entity-search/subject
Find newsletter and podcast articles tagged with a theme or subject.
Use `GET /api/v1/entities/search` with a `subject` to find curated articles
whose extracted themes mention a topic — a case-insensitive substring match
against `metadataJson.themes`. Unlike `ticker` / `person` / `company` /
`organization`, subject-only queries do not fill `matchedEntity`.
Limited to enabled publications curated for chat. Free, no auth required.
## Request
The endpoint requires at least one of `ticker`, `company`, `person`,
`organization`, `subject`, or `author`. Multiple entity inputs are matched
as alternatives; `author` and the other filters narrow the results.
```bash theme={null}
curl "https://dripstack.com/api/v1/entities/search?subject=semiconductors&limit=5"
```
| Parameter | Required | Description |
| - | - | - |
| `subject` | one of | Theme or subject, minimum 2 characters |
| `author` | one of | Source article author, minimum 2 characters, matched as a case-insensitive substring |
| `stockPicksOnly` | optional | `true` or `false` (default); only return articles linked to a stock pick when true |
| `sort` | optional | `latest` (default) or `earliest`, ordered by publication date |
| `publicationSlug` | optional | Restrict results to one publication |
| `publishedAfter` / `publishedBefore` | optional | `YYYY-MM-DD`, inclusive UTC calendar day bounds |
| `limit` | optional | 1-30, defaults to 10 |
| `cursor` | optional | Pass the previous response's `nextCursor` to fetch the next page |
Set `sort=earliest` for oldest first. Keep the same filters and sort when
following `nextCursor`. Invalid parameters, reversed date bounds, or an invalid
cursor return `400`.
## Response
```json theme={null}
{
"query": {
"ticker": null,
"company": null,
"person": null,
"organization": null,
"subject": "semiconductors",
"author": null,
"stockPicksOnly": false,
"sort": "latest",
"publicationSlug": null,
"publishedAfter": null,
"publishedBefore": null
},
"matchedEntity": null,
"count": 1,
"nextCursor": null,
"items": [
{
"publicationSlug": "stratechery",
"slug": "chip-cycle",
"title": "The Semiconductor Cycle",
"author": "Ben Thompson",
"publishedAt": "2026-06-12T00:00:00.000Z",
"priceCents": 500,
"url": "https://stratechery.com/p/chip-cycle",
"isPodcast": false
}
]
}
```
Results are sorted by `publishedAt`, most recent first by default (`sort=latest`).
Use this to browse a named theme by recency. Broad "what are analysts saying about X?" research
still belongs on `/api/v1/search`.
# Search Articles by Ticker
Source: https://docs.dripstack.com/entity-search/ticker
Find newsletter and podcast articles that mention a specific stock ticker.
Use `GET /api/v1/entities/search` with a `ticker` to find curated indexed
articles that mention a stock symbol — useful for answering "what did analysts
say about \$TICKER this week?" without scanning topic search results by hand.
Limited to enabled publications curated for chat. Free, no auth required.
## Request
The endpoint requires at least one of `ticker`, `company`, `person`,
`organization`, `subject`, or `author`. Multiple entity inputs are matched
as alternatives; `author` and the other filters narrow the results.
```bash theme={null}
curl "https://dripstack.com/api/v1/entities/search?ticker=AAPL&limit=5"
```
| Parameter | Required | Description |
| - | - | - |
| `ticker` | one of | Stock ticker, 1-8 characters (letters/numbers/`.`/`-`) |
| `author` | one of | Source article author, minimum 2 characters, matched as a case-insensitive substring |
| `stockPicksOnly` | optional | `true` or `false` (default); only return articles linked to a stock pick when true |
| `sort` | optional | `latest` (default) or `earliest`, ordered by publication date |
| `publicationSlug` | optional | Restrict results to one publication |
| `publishedAfter` / `publishedBefore` | optional | `YYYY-MM-DD`, inclusive UTC calendar day bounds |
| `limit` | optional | 1-30, defaults to 10 |
| `cursor` | optional | Pass the previous response's `nextCursor` to fetch the next page |
Set `sort=earliest` for oldest first. Keep the same filters and sort when
following `nextCursor`. Invalid parameters, reversed date bounds, or an invalid
cursor return `400`.
## Response
```json theme={null}
{
"query": {
"ticker": "AAPL",
"company": null,
"person": null,
"organization": null,
"subject": null,
"author": null,
"stockPicksOnly": false,
"sort": "latest",
"publicationSlug": null,
"publishedAfter": null,
"publishedBefore": null
},
"matchedEntity": {
"kind": "company",
"name": "Apple",
"description": "American multinational technology company",
"companies": [{ "name": "Apple", "ticker": "AAPL" }],
"tickers": ["AAPL"],
"matchedVia": ["ticker", "company"]
},
"count": 1,
"nextCursor": null,
"items": [
{
"publicationSlug": "stratechery",
"slug": "aapl-earnings-recap",
"title": "Apple's Earnings Recap",
"author": "Ben Thompson",
"publishedAt": "2026-08-15T00:00:00.000Z",
"priceCents": 500,
"url": "https://stratechery.com/p/aapl-earnings-recap",
"isPodcast": false
}
]
}
```
Results are sorted by `publishedAt`, most recent first by default (`sort=latest`).
For relevance ranking, use `/api/v1/search`. `priceCents` is the price to unlock the paid post response;
the search itself is free. `isPodcast` is true for podcast episodes — the
paid post response then includes a `transcript` when ready.
## Ticker matching
`ticker` is matched against the tickers Drip has already extracted for each
article, uppercased before comparison. When a company listing is known, the
ticker also resolves a company card (`matchedEntity`) and ORs in that company
name, so articles tagged only as "Apple" are included with `$AAPL`.
`matchedEntity` is `null` when that lookup misses; the raw ticker is still
searched.
With `stockPicksOnly=true`, `ticker` must match a linked stock pick's ticker
exactly (case-insensitive). Ticker-only searches in this mode do not expand
to company-name tags. Additional company, person, organization, or subject
inputs still filter the article's metadata or title.
# Overview
Source: https://docs.dripstack.com/index
Pay-once article summaries for agents researching financial newsletters and blogs.
Drip gives AI agents pay-once access to robust summaries of premium financial
newsletter and blog articles. Discover relevant posts for free, then pay when
your agent requests an article summary for its research.
Each first successful paid fetch of a post summary unlocks that post forever for
the paying subject. Later fetches of the same post return the live summary with
no charge.
## How it works
1. **Search or target a publication** — search across all supported financial
newsletters and blogs for relevant posts, or query specific publications.
Discovery routes are free.
2. **Inspect the price** — article prices appear as `priceCents` when you list a
publication or search for posts. Clients can also inspect the authoritative price in the
runtime `402` response before paying.
3. **Pay & retrieve the summary** — request a robust article summary using
[x402 on Base or Solana, or MPP on Tempo or Stripe](/concepts/payment-flow), or authenticate with
an [API key backed by account credits](/quickstart-api-keys). The first
successful pay unlocks that post forever for that Drip user (API key / JWT /
MCP OAuth share the same account) or wallet/MPP credential. x402 and MPP
clients should store `X-Drip-Unlock` / `unlockToken` for free re-reads.
## More discovery routes
Topic search is the default. These routes cover the other free questions:
| Question | Route | Guide |
| - | - | - |
| Articles about a **topic** | `GET /api/v1/search` | [Topic Search](/search) |
| Named newsletter, author, or catalog browse | `GET /api/v1/publications/search` or `GET /api/v1/publications` | [Publications](/publications) |
| Who is **NVDA** / nvidia.com? | `GET /api/v1/companies` | [Company Lookup](/companies) |
| Articles that **mention** a ticker, company, person, org, or theme | `GET /api/v1/entities/search` | [Entity Search](/entity-search/ticker) |
| Popular posts or publications | `GET /api/v1/posts/top-selling` or `GET /api/v1/publications/top-selling` | [Top-selling](/top-selling) |
Company lookup is an identity card, not article search. After you have a
ticker, use entity search for mentioning articles.
For ticker-level analyst calls, use `GET /api/v2/stock-picks` (preferred) or
`GET /api/v1/stock-picks`. These return [Stock Picks](/stock-picks) through
subscription access (V2) or per-request payment. A paid bundle does not grant
lifetime unlocks for its source posts.
## Account, credits, and past purchases
API keys and MCP OAuth tokens for the same account share one Drip user.
The account routes below reject session JWTs.
| Need | Route | Guide |
| - | - | - |
| Who is this credential? | `GET /api/v1/me` | [Account](/account) |
| Credit balance and top-up URL | `GET /api/v1/me/credits` | [Credits](/credits) |
| Credit ledger | `GET /api/v1/me/credits/activity` | [Credits](/credits#ledger) |
| Posts this account already unlocked | `GET /api/v1/me/unlocks` | [Unlocks](/unlocks) |
There is no top-up API — send users to `topUpUrl`. Unlocks are metadata only;
the summary still comes from the paid post route.
Hosted MCP at `https://dripstack.com/api/mcp` mirrors the same HTTP routes
(`search_posts`, `search_entities`, `search_companies`, `unlock_post`, …).
Discovery tools need no auth; account and paid tools need OAuth or
`Bearer pk_drip_…`.
Search, inspect the price, and retrieve an article summary with a payment-aware client.
Use a bearer API key and account credits to retrieve paid article summaries.
Publications, posts, search, and paid article summaries.
Relevance-ranked posts for a topic across supported newsletters and podcasts.
Find a named source, browse the catalog, or list recent posts.
Most purchased posts and highest-earning publications.
Ticker-level analyst calls and long/short ideas — V2 subscription or x402, legacy V1.
Structured research feeds such as top-selling.
Wallet payment challenges, API-key credits, and status codes.
Handle failures safely across discovery, credits, x402, and MPP.
The OpenAPI 3.1 document, including paid-route payment metadata.
Identity card for a ticker, domain, qid, CIK, or name — not article search.
Recency-ranked articles that mention a ticker, company, person, organization, or subject.
Auth introspection, credits, ledger, and lifetime unlocks for an API key or MCP token.
# Publications
Source: https://docs.dripstack.com/publications
Browse or search the curated catalog, then list recent posts for one source.
Use these routes when the user names a **newsletter, author, podcast, or
URL**, or asks what publications are available. Do not load the full catalog
for a topic question — use [Topic Search](/search) instead.
Free, no auth.
MCP: `list_publications`, `search_publications`, `get_publication`,
`list_podcasts`, `get_podcast`.
## Find a publication by name
`GET /api/v1/publications/search?q=...` — `q` is required (minimum 2
characters). Returns up to 3 matches.
```bash theme={null}
curl "https://dripstack.com/api/v1/publications/search?q=Unchained"
```
```json theme={null}
{
"query": "Unchained",
"count": 1,
"items": [
{
"publicationSlug": "unchainedcrypto.beehiiv.com",
"title": "Unchained Daily Newsletter",
"author": "Unchained",
"siteUrl": "https://unchainedcrypto.beehiiv.com"
}
]
}
```
## One publication and its recent posts
`GET /api/v1/publications/{publicationSlug}` works for any enabled indexed
publication, including publications outside the curated list. Optional `limit`
is 1-100; omitting it returns all posts with ready synthesized summaries,
newest first.
```bash theme={null}
curl "https://dripstack.com/api/v1/publications/unchainedcrypto.beehiiv.com?limit=20"
```
The response includes publication metadata plus `posts[]` with `slug`,
`title`, `subtitle`, `publishedAt`, `priceCents`, and `isPodcast`. Only posts
with ready synthesized summaries are listed; the summaries themselves require
the paid post route. Unknown or disabled slugs return `404`. Invalid `limit`
values return `400`.
Unlock a selected post with
`GET /api/v1/publications/{publicationSlug}/{postSlug}` after confirming
`$X.XX` from `priceCents`. See [Payment Flow](/concepts/payment-flow).
## Browse the curated catalog
`GET /api/v1/publications` lists enabled, chat-curated newsletters, podcasts, and
publications (`slug`, `title`, `description`, `siteUrl`, `lastSyncedAt`).
Use this only when the user explicitly wants to browse what is available.
```bash theme={null}
curl "https://dripstack.com/api/v1/publications"
```
## Podcasts
Same JSON envelope as publications (`{ "publications": [...] }`).
```bash theme={null}
curl "https://dripstack.com/api/v1/podcasts"
curl "https://dripstack.com/api/v1/podcasts/{publicationSlug}?limit=20"
```
`GET /api/v1/podcasts/{publicationSlug}` returns `404` unless the slug is an
enabled podcast. The same `limit` and ready-summary rules apply as for
publication details. Unlock episodes with the same paid publication-post route as
newsletters.
# Quickstart: x402 / MPP
Source: https://docs.dripstack.com/quickstart
Give your agent a wallet to pay for robust financial newsletter summaries with x402 on Base or Solana, or MPP on Tempo.
## Pay with a wallet-aware client
Your agent needs a funded wallet and a payment-aware HTTP client. The examples
below complete the same research workflow:
1. Search for recent posts about Michael Burry for free.
2. Select the highest-ranked result.
3. Inspect the search result's `priceCents`.
4. Request the paid route without credentials and inspect the authoritative
price in the `402` challenge.
5. Let the wallet-aware client pay and retry the request.
6. Use the returned `synthesizedSummary` in the research workflow.
Every **first** successful pay for a given post unlocks that summary forever for
the paying wallet or MPP credential. Store `unlockToken` from the JSON body (or
the `X-Drip-Unlock` response header) and resend it as the request header
`X-Drip-Unlock` on later fetches for a free re-read. If you lose the token but
retry with the same wallet payment (x402) or a validated MPP credential, the
server skips the charge and re-issues a token. The response contains a robust
summary and source metadata.
Before using these examples in production, review the paid-request guidance in
[Errors & Retries](/concepts/errors-retries).
Uses the x402 protocol with USDC on Base or Solana (both appear in the live
`402` challenge).
```bash theme={null}
bun add viem @solana/kit @scure/base @x402/core @x402/evm @x402/svm @x402/fetch
```
```typescript theme={null}
import { privateKeyToAccount } from "viem/accounts";
import { createKeyPairSignerFromBytes } from "@solana/kit";
import { base58 } from "@scure/base";
import { x402Client } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { ExactSvmScheme } from "@x402/svm/exact/client";
import { wrapFetchWithPayment } from "@x402/fetch";
const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
// 64-byte base58 secret key (private + public)
const svmSigner = await createKeyPairSignerFromBytes(
base58.decode("YOUR_SOLANA_BASE58_SECRET_KEY"),
);
const client = new x402Client();
const evmScheme = new ExactEvmScheme(account);
client.register("eip155:8453", evmScheme); // 84532 for testnet
client.register(
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // EtWTRABZaYq6iMfeYKouRu166VU2xqa1 for testnet
new ExactSvmScheme(svmSigner),
);
const payFetch = wrapFetchWithPayment(fetch, client);
const baseUrl = "https://dripstack.com";
const searchResponse = await fetch(
`${baseUrl}/api/v1/search?q=Michael%20Burry&limit=5`,
);
const search = await searchResponse.json();
const firstPost = search.items[0];
if (!firstPost) {
throw new Error("No Michael Burry posts found.");
}
const articleUrl = `${baseUrl}/api/v1/publications/${firstPost.publicationSlug}/${firstPost.slug}`;
// Search returns the effective discovery price for this post.
console.log("Selected:", firstPost.title);
console.log("Listed price (cents):", firstPost.priceCents);
// A plain request exposes the authoritative x402 price before payment.
const challengeResponse = await fetch(articleUrl);
if (challengeResponse.status !== 402) {
throw new Error(`Expected 402 challenge, got ${challengeResponse.status}`);
}
console.log(
"x402 challenge:",
challengeResponse.headers.get("PAYMENT-REQUIRED"),
);
// The wallet-aware client handles the challenge, pays, and retries.
const articleResponse = await payFetch(articleUrl);
if (!articleResponse.ok) {
throw new Error(`Paid request failed: ${articleResponse.status}`);
}
const article = await articleResponse.json();
console.log(article.title);
console.log(article.synthesizedSummary);
// First settle issues an unlock token — later fetches are free (no charge).
const unlockToken =
article.unlockToken ?? articleResponse.headers.get("X-Drip-Unlock");
if (!unlockToken) {
throw new Error("Expected unlockToken / X-Drip-Unlock on first settle");
}
const freeResponse = await fetch(articleUrl, {
headers: { "X-Drip-Unlock": unlockToken },
});
if (!freeResponse.ok) {
throw new Error(`Unlock re-read failed: ${freeResponse.status}`);
}
const freeArticle = await freeResponse.json();
console.log("Re-read protocol:", freeArticle.paymentInfo?.protocol); // "unlock"
```
Uses MPP with a wallet on Tempo.
```bash theme={null}
bun add viem mppx
```
```typescript theme={null}
import { privateKeyToAccount } from "viem/accounts";
import { Mppx, tempo } from "mppx/client";
const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const mppx = Mppx.create({
methods: [tempo({ account })],
polyfill: false,
});
const baseUrl = "https://dripstack.com";
const searchResponse = await fetch(
`${baseUrl}/api/v1/search?q=Michael%20Burry&limit=5`,
);
const search = await searchResponse.json();
const firstPost = search.items[0];
if (!firstPost) {
throw new Error("No Michael Burry posts found.");
}
const articleUrl = `${baseUrl}/api/v1/publications/${firstPost.publicationSlug}/${firstPost.slug}`;
// Search returns the effective discovery price for this post.
console.log("Selected:", firstPost.title);
console.log("Listed price (cents):", firstPost.priceCents);
// A plain request exposes the authoritative MPP price before payment.
const challengeResponse = await fetch(articleUrl);
if (challengeResponse.status !== 402) {
throw new Error(`Expected 402 challenge, got ${challengeResponse.status}`);
}
console.log(
"MPP challenge:",
challengeResponse.headers.get("WWW-Authenticate"),
);
// The wallet-aware client handles the challenge, pays, and retries.
const articleResponse = await mppx.fetch(articleUrl);
if (!articleResponse.ok) {
throw new Error(`Paid request failed: ${articleResponse.status}`);
}
const article = await articleResponse.json();
console.log(article.title);
console.log(article.synthesizedSummary);
// First settle issues an unlock token — later fetches are free (no charge).
const unlockToken =
article.unlockToken ?? articleResponse.headers.get("X-Drip-Unlock");
if (!unlockToken) {
throw new Error("Expected unlockToken / X-Drip-Unlock on first settle");
}
const freeResponse = await fetch(articleUrl, {
headers: { "X-Drip-Unlock": unlockToken },
});
if (!freeResponse.ok) {
throw new Error(`Unlock re-read failed: ${freeResponse.status}`);
}
const freeArticle = await freeResponse.json();
console.log("Re-read protocol:", freeArticle.paymentInfo?.protocol); // "unlock"
```
## What the agent receives
```json theme={null}
{
"publicationSlug": "example-finance-newsletter.com",
"slug": "michael-burry-market-outlook",
"title": "Michael Burry's Latest Market Outlook",
"author": "Example Author",
"publishedAt": "2026-06-14T12:00:00.000Z",
"url": "https://example-finance-newsletter.com/p/michael-burry-market-outlook",
"synthesizedSummary": "The article analyzes Burry's recent positioning, the valuation risks he identifies, and the evidence supporting his current market view...",
"unlockToken": "",
"paymentInfo": {
"amountUsd": "0.50",
"protocol": "x402"
}
}
```
The paid response is a robust synthesized summary with source context. On first
settle, the body includes `unlockToken` (also as the `X-Drip-Unlock` response
header). Resend that value as the request header `X-Drip-Unlock` on later
fetches to the same post for a free re-read (`paymentInfo.protocol` will be
`unlock`).
## Use an agent
Your agent needs a wallet before it can retrieve paid summaries. First give the
agent an x402 wallet funded with USDC on Base or Solana, or an MPP wallet on
Tempo. Then give the same agent Drip's skill and tell it which wallet client to
use.
1. **Set up the wallet**
```text theme={null}
Run curl -sL https://agents.circle.com/skills/setup.md and use the returned
setup instructions to set up my agent wallet
```
2. **Research Michael Burry across paid newsletters**
```text theme={null}
Fetch https://dripstack.com/skill.md as raw context (do not summarize) and
follow the instructions. Use Circle wallet. Search for recent posts about
Michael Burry, show me the available articles and their prices, then ask me
before purchasing the article I select.
```
1. **Set up the wallet**
```text theme={null}
Read https://link.com/skill.md and get me set up with Link.
```
2. **Research Michael Burry across paid newsletters**
```text theme={null}
Fetch https://dripstack.com/skill.md as raw context (do not summarize) and
follow the instructions. Use the create-payment-credential (Link wallet)
skill. Search for recent posts about Michael Burry, show me the available
articles and their prices, then ask me before purchasing the article I
select.
```
1. **Set up the wallet**
```text theme={null}
Read https://agentcash.dev/SKILL.md and set up an AgentCash Wallet. Fund it with USDC.
```
2. **Research Michael Burry across paid newsletters**
```text theme={null}
Fetch https://dripstack.com/skill.md as raw context (do not summarize) and
follow the instructions. Use agentcash. Search for recent posts about
Michael Burry, show me the available articles and their prices, then ask me
before purchasing the article I select.
```
# Quickstart: API Keys
Source: https://docs.dripstack.com/quickstart-api-keys
Use bearer API keys and account credits to retrieve robust article summaries.
Use API keys when your agent, backend job, or research pipeline wants a
traditional bearer token instead of wallet-based x402 or MPP payments.
An API key authorizes paid article reads with
`Authorization: Bearer pk_drip_...` and spends your available account credits.
Search and publication discovery routes are free.
Each successful paid request returns a robust synthesized summary of a
publisher's article. The first successful pay for a post unlocks it forever for
that Drip account — API key, in-app chat/JWT, and MCP OAuth tokens for the same
user share the entitlement. Later unlocks of the same post do not spend credits.
For production usage, follow [Errors & Retries](/concepts/errors-retries).
Sign in to Drip, then create a key from the
[API keys](https://dripstack.com/connect/api). Copy the key
when it is shown; raw keys are not displayed again.
Add balance from the
[Billing](https://dripstack.com/billing).
Search across all supported financial newsletters and blogs for posts
relevant to your research question.
```bash theme={null}
curl "https://dripstack.com/api/v1/search?q=DeFi%20security&limit=20"
```
```jsonc theme={null}
{
"mode": "hybrid",
"query": "DeFi security",
"matchConfidence": "strong",
"count": 20,
"items": [
{
"publicationSlug": "unchainedcrypto.beehiiv.com",
"slug": "defi-united-unveils-plan-to-restore-rseth-after-292m-kelp-dao-exploit",
"title": "DeFi United Unveils Plan to Restore rsETH After $292M Kelp DAO Exploit",
"publishedAt": "2026-04-28T11:00:00.000Z"
},
{
"publicationSlug": "unchainedcrypto.beehiiv.com",
"slug": "the-kelp-dao-exploit-bill-is-coming-due",
"title": "The Kelp DAO Exploit Bill Is Coming Due",
"publishedAt": "2026-04-21T11:00:56.000Z"
}
// ...18 more results
]
}
```
Each result includes `publicationSlug` and `slug`. Use those two values to
build the paid article URL. Search results are candidates, not paid article
summaries.
If you already know which source you care about, find the publication slug
and list its ready posts.
```bash theme={null}
curl "https://dripstack.com/api/v1/publications/search?q=Unchained%20Daily%20Newsletter"
```
```bash theme={null}
curl "https://dripstack.com/api/v1/publications/unchainedcrypto.beehiiv.com?limit=20"
```
```jsonc theme={null}
{
"slug": "unchainedcrypto.beehiiv.com",
"title": "Unchained Daily Newsletter",
"posts": [
{
"slug": "defi-united-unveils-plan-to-restore-rseth-after-292m-kelp-dao-exploit",
"title": "DeFi United Unveils Plan to Restore rsETH After $292M Kelp DAO Exploit",
"publishedAt": "2026-04-28T11:00:00.000Z",
"priceCents": 50
},
{
"slug": "fork-in-the-road",
"title": "Fork in the Road",
"publishedAt": "2026-04-27T11:30:00.000Z",
"priceCents": 50
}
// ...18 more posts
]
}
```
The publication response includes recent posts with `slug`, `title`,
`publishedAt`, and effective `priceCents` (post override, publication default,
or platform default). Search results also include `priceCents`. To verify
the runtime price before spending, request the paid URL without your API
key and inspect its `402` challenge, then send the authenticated request.
Use the `publicationSlug` and `slug` from search or publication lookup to
call the paid article route. A successful response returns `200` with
article metadata and `synthesizedSummary`. The first successful pay for a
post unlocks it forever for this Drip account; later requests for the same
post do not spend credits.
## Request examples
```bash theme={null}
export DRIP_API_KEY="pk_drip_YOUR_KEY"
export PUBLICATION_SLUG="unchainedcrypto.beehiiv.com"
export POST_SLUG="defi-united-unveils-plan-to-restore-rseth-after-292m-kelp-dao-exploit"
curl -s \
"https://dripstack.com/api/v1/publications/$PUBLICATION_SLUG/$POST_SLUG" \
-H "Authorization: Bearer $DRIP_API_KEY"
```
```typescript theme={null}
const baseUrl = "https://dripstack.com";
const publicationSlug = "unchainedcrypto.beehiiv.com";
const postSlug =
"defi-united-unveils-plan-to-restore-rseth-after-292m-kelp-dao-exploit";
const response = await fetch(
`${baseUrl}/api/v1/publications/${publicationSlug}/${postSlug}`,
{
headers: {
Authorization: `Bearer ${process.env.DRIP_API_KEY}`,
},
},
);
if (response.status === 403) {
throw new Error("Insufficient credits. Top up before retrying.");
}
if (!response.ok) {
throw new Error(`Drip request failed: ${response.status}`);
}
const post = await response.json();
console.log(post.title);
console.log(post.synthesizedSummary);
```
```bash theme={null}
pip install requests
```
```python theme={null}
import os
import requests
base_url = "https://dripstack.com"
publication_slug = "unchainedcrypto.beehiiv.com"
post_slug = (
"defi-united-unveils-plan-to-restore-rseth-after-292m-kelp-dao-exploit"
)
response = requests.get(
f"{base_url}/api/v1/publications/{publication_slug}/{post_slug}",
headers={"Authorization": f"Bearer {os.environ['DRIP_API_KEY']}"},
timeout=30,
)
if response.status_code == 403:
raise RuntimeError("Insufficient credits. Top up before retrying.")
response.raise_for_status()
post = response.json()
print(post["title"])
print(post["synthesizedSummary"])
```
## Example response
```json theme={null}
{
"publicationSlug": "unchainedcrypto.beehiiv.com",
"slug": "defi-united-unveils-plan-to-restore-rseth-after-292m-kelp-dao-exploit",
"title": "DeFi United Unveils Plan to Restore rsETH After $292M Kelp DAO Exploit",
"author": "Unchained Daily",
"publishedAt": "2026-04-28T11:00:00.000Z",
"url": "https://unchainedcrypto.beehiiv.com/p/defi-united-unveils-plan-to-restore-rseth-after-292m-kelp-dao-exploit",
"synthesizedSummary": "The article explains DeFi United's recovery proposal following the Kelp DAO exploit, including how affected rsETH holders may be made whole...",
"paymentInfo": {
"amountUsd": "0.50",
"protocol": "mpp",
"settledAt": "2026-06-15T10:30:00.000Z"
}
}
```
The response contains a robust synthesized summary and source metadata. The
first successful pay unlocks that post forever for this Drip account; repeating
the request for the same post does not spend credits again (`paymentInfo.protocol`
is `unlock`, and `unlocked` is `true`).
On the first paid response, `paymentInfo.protocol` can be `mpp` when Drip
completes the credit-funded payment through MPP, or `credits` otherwise. Both
spend your account balance. `spendSource` is not returned. Inspect
[credit activity](/credits#ledger) for the debit.
## Common responses
| Status | Meaning | Action |
| - | - | - |
| `200` | Summary returned (charged on first unlock) | Use `synthesizedSummary` in research |
| `401` | Invalid API key | Check the bearer token |
| `403` | Insufficient credits | Top up account credits |
| `404` | Post or publication missing | Verify `publicationSlug` and `postSlug` |
| `503` | Summary is not ready | Retry later; no credits were charged |
Keep API keys server-side. Do not ship `pk_drip_...` keys in browser code, public repositories, or
agent traces.
## Error response examples
An invalid or revoked API key returns:
```json theme={null}
{
"error": "Unauthorized: API key not found. Create one at /connect/api or reconnect via mcp login.",
"code": "unauthorized",
"hint": "Send Authorization: Bearer pk_drip_… or an OAuth access token (mcp_at_…). See /llms.txt."
}
```
If the summary has not finished processing, no credits are charged:
```json theme={null}
{
"error": "Post summary is not ready yet.",
"code": "summary_not_ready",
"hint": "Retry later; the summary is still being generated."
}
```
# Topic Search
Source: https://docs.dripstack.com/search
Search indexed newsletters and podcasts by topic. Free, ranked by relevance.
`GET /api/v1/search` is the default discovery route. Use it when the question is
a **topic** ("what are writers saying about AI capex?") rather than a ticker,
person, or named publication.
Free, no auth. Results are **candidates** — ranked post cards with
`priceCents`. The `synthesizedSummary` still comes from the
[paid publication-post route](/concepts/payment-flow).
MCP: `search_posts`.
## Request
`q` is required (minimum 2 characters). Default `limit` is 10.
```bash theme={null}
curl "https://dripstack.com/api/v1/search?q=AI%20infrastructure%20spending&limit=10"
```
| Parameter | Required | Description |
| - | - | - |
| `q` | yes | Natural-language query, minimum 2 characters |
| `limit` | optional | 1-30, defaults to 10 |
| `mode` | optional | `hybrid` (default) blends lexical and semantic; `fts` is lexical only |
| `platform` | optional | `substack`, `beehiiv`, `rss`, `podcast`, `email`, or `twitter` |
| `source` | optional | `newsletter`, `podcast`, or `all`. `newsletter` covers Substack, Beehiiv, RSS, email, and Twitter |
| `publicationSlug` | optional | Restrict results to one publication |
| `publishedAfter` / `publishedBefore` | optional | `YYYY-MM-DD`, inclusive UTC calendar day bounds |
Do not combine a `platform` that conflicts with `source` (for example
`platform=podcast` with `source=newsletter`) — that returns `400`.
`publishedAfter` must not be later than `publishedBefore`.
Search starts with publications curated for chat and can fall back to other
indexed publications when the initial matches are weak. `publicationSlug`
restricts the search to that publication. Disabled publications are excluded
from returned items.
## Response
```json theme={null}
{
"mode": "hybrid",
"asOf": "2026-06-15T10:30:00Z",
"query": "AI infrastructure spending",
"normalizedQuery": "ai infrastructure spending",
"matchConfidence": "strong",
"searchTierUsed": "scoped",
"timeWindow": null,
"freshnessCoverage": null,
"count": 1,
"totalCount": 1,
"items": [
{
"publicationSlug": "stratechery",
"slug": "the-ai-infrastructure-boom",
"title": "The AI Infrastructure Boom",
"subtitle": "Why hyperscalers are spending billions on GPU clusters",
"priceCents": 50,
"isPodcast": false,
"isScopedPublisher": true,
"relevanceScore": 42,
"matchedTokenCount": 2,
"totalTokenCount": 3,
"topicCoverageRatio": 0.6666666666666666,
"snippet": "Nvidia's datacenter revenue hit $26B last quarter as hyperscalers race to build out GPU clusters...",
"whyMatched": ["Title matches AI + infrastructure"],
"publishedAt": "2026-06-14T12:00:00Z"
}
]
}
```
`matchConfidence` is `strong`, `weak`, or `none`. Present each item as
`{title} ({publicationSlug}, YYYY-MM-DD) — $X.XX` when `priceCents` is known.
Keep `publicationSlug` + `slug` for the paid fetch.
`searchTierUsed` is `scoped` or `non_scoped`. `timeWindow` describes a date
window inferred from the query, or is `null`; `freshnessCoverage` reports
coverage of that window and whether older results were used as a fallback.
`count` is the number of returned items. `totalCount` is the number of ranked
candidates before the response limit and disabled-publication filter, not a
count of every matching article in the catalog.
`isPodcast` is true for episodes — the paid post response then includes a
`transcript` when ready.
Invalid params return `400`. Unexpected failures return `500` with
`error: "Search failed. Please retry."`, `code: "internal_error"`, and a
recovery `hint`.
## Topic search vs entity search vs company lookup
| Question | Route |
| - | - |
| What are writers saying about **this topic**? | This page — `GET /api/v1/search` |
| Articles that **mention** a ticker, company, person, org, or theme | [Entity Search](/entity-search/ticker) — recency, not relevance |
| Who **is** NVDA / nvidia.com? | [Company Lookup](/companies) — identity card, not articles |
# Stock Picks
Source: https://docs.dripstack.com/stock-picks
Ticker-level analyst calls with two API versions: V2 (subscription, credits, or x402 pay-per-use) and legacy V1 (single-day paid).
A **stock pick** is a ticker-level call extracted from a source article — an
analyst recommendation, a long/short idea, an add, or an exit. Drip serves
these as structured JSON for AI agents, separate from the newsletter/article
workflow.
There are two API versions. Use **V2**; V1 exists for existing integrations and
stays available for those integrations. Other documented API routes continue to use `/api/v1`.
| | V2 (recommended) | V1 (legacy) |
| - | - | - |
| Routes | `GET /api/v2/stock-picks` · `GET /api/v2/stock-picks/quote` | `GET /api/v1/stock-picks` · `GET /api/v1/stock-picks/quote` |
| Access model | Subscription (PRO/EXPERT), credits, or x402 pay-per-use | Credits / x402 / MPP pay-per-use |
| Time coverage | One day **or** date ranges (`from`/`to`) | One UTC calendar day only |
| Filters, search, pagination | PRO/EXPERT only | ❌ |
| Response envelope | `meta` + `pagination` + `picks[]` | `dateUsed` + `count` + `items[]` |
| Status | Active | Deprecated for new integrations (still available) |
## V2 — `GET /api/v2/stock-picks`
The recommended endpoint. It resolves the caller's plan from the bearer
credential first, then either serves the request from the subscription window
**free of charge** or routes anonymous / FREE callers through the same
pay-per-use flow as V1.
### Subscription access (Bearer API key, OAuth token, or session JWT)
* **EXPERT** readers get full history. **PRO** is clamped to the live 7-day
window.
* In-plan requests are **never charged** and count against the API key's
monthly request allowance (`429` when exhausted).
* An explicit `date` outside the plan window returns `403`; out-of-window
ranges are clamped to the allowed window. A PRO range with no overlap returns
`403` — read `meta.allowedRange` / `meta.appliedRange`.
```bash theme={null}
# Latest picks in-window (free for PRO/EXPERT subscribers)
curl -H "Authorization: Bearer pk_drip_..." \
"https://dripstack.com/api/v2/stock-picks"
# Historical range (EXPERT); 3 days per page, sorted oldest-first within each page
curl -H "Authorization: Bearer pk_drip_..." \
"https://dripstack.com/api/v2/stock-picks?from=2026-05-01&to=2026-05-31&sort=oldest&limitDays=3"
```
### Pay-per-use (anonymous or FREE)
No free API access. Call the free quote, confirm the `amountUsd`, then pay with
an x402 client or a bearer credential backed by Drip credits. Freeze the quote's
`dateUsed` and use the same `limit` on the paid request. The paid path selects
one day using `date` / `limit`; `sort` orders that day's rows. Ranges, author /
direction / query filters, pagination, and prices apply to subscription reads
and are ignored on the paid path.
Stock-pick bundles are charged per request. A purchase does not create a
lifetime post unlock.
```bash theme={null}
# 1. Free preflight — inspect amountUsd and dateUsed before approving payment
curl "https://dripstack.com/api/v2/stock-picks/quote?date=2026-05-30&limit=200"
# 2. After approval, use the returned dateUsed and the same limit
# This bearer example spends Drip credits for a caller without a paid plan.
curl -H "Authorization: Bearer $DRIP_API_KEY" \
"https://dripstack.com/api/v2/stock-picks?date=2026-05-30&limit=200"
```
### V2 query parameters
| Param | Meaning |
| - | - |
| `date` | One UTC day (mutually exclusive with `from`/`to`) |
| `from` / `to` | Inclusive UTC day range, clamped to the caller's plan window |
| `limit` | Max pick rows per day (1-500, default 200) |
| `limitDays` | Max days per range page (1-30, default 7); pass `cursor` to page older |
| `cursor` | Older-than marker from the previous response's `pagination.nextCursor` |
| `author` | Exact author name filter (paid tiers) |
| `direction` | `LONG` or `SHORT` (paid tiers) |
| `query` | Case-insensitive substring over ticker, author, publication title (paid tiers) |
| `sort` | `newest` (default) or `oldest` within each page; pages always move toward older days |
| `includePrices` | Pass `false` to omit prices; otherwise historical subscriber picks may include verified asset prices |
Each `picks[]` item includes `date`, `ticker`, `direction`, `action`, `author`,
`publicationSlug`, `publicationTitle`, `articleUrl` (Drip's sellable URL when a
post is attributed), `conviction`, `convictionLabel`, `evidenceQuote`,
`rationaleSnippet`, `publishedAt`, `tickerExchange`, `instrumentType`,
`assetId`, `assetResolutionStatus`, and `asset`.
`assetResolutionStatus` is `RESOLVED`, `UNRESOLVED`, or `PENDING`. Use `assetId`
and `asset` (`id`, `name`, `kind`, `symbol`, `exchangeMic`, `currency`) for
identity; a ticker alone can refer to different assets. `asset` and `assetId`
are null until resolved. `instrumentType` is the legacy extraction type;
`asset.kind` identifies resolved equities, ETFs, or crypto.
Historical subscription reads may also include `prices` (`entry`, `current`,
`returnPct`, `currency`). Returns are direction-adjusted. Prices are omitted
for the current day, pay-per-use requests, `includePrices=false`, unresolved
assets, and unavailable or mismatched provider data.
A successful subscription query can return `picks: []`. On the paid path,
no matching picks returns `404`. Free quote responses include `dateUsed`,
`startDate`, `endDate`, `asOf`, `count`, `attributedPostCount`, `amountUsd`, and
`posts[]` containing `publicationSlug` and per-source `amountUsd`; quotes do not
expose post slugs or pick rows.
V2 errors: `400` invalid query, `401` bad bearer, `402` payment required,
`403` outside the plan window or insufficient credits, `404` no picks (paid path),
`429` request allowance exhausted.
## V1 — `GET /api/v1/stock-picks` (legacy, still available)
The original endpoint. It always returns **one effective UTC calendar day** —
the latest day with picks by default, or `date=YYYY-MM-DD` for a specific day.
Pricing is a flat unit price × the number of distinct attributed source
articles in the response; call `GET /api/v1/stock-picks/quote` for the exact
total, then pass the quoted `dateUsed` on the paid request. A `404` means no
picks exist for that day — do not pay.
```bash theme={null}
# Free preflight
curl "https://dripstack.com/api/v1/stock-picks/quote?date=2026-05-30&limit=200"
# After approval, freeze the returned dateUsed and the same limit
curl -H "Authorization: Bearer $DRIP_API_KEY" \
"https://dripstack.com/api/v1/stock-picks?date=2026-05-30&limit=200"
```
Response: `dateUsed`, `startDate`, `endDate`, `asOf`, `count`, and `items[]`
with `ticker`, `tickerExchange`, `instrumentType`, `action`, `direction`,
`authorConviction`, `convictionLabel`, `activePick`, `evidenceQuote`,
`rationaleSnippet`, `articleTitle`, `articleUrl`, `author`, `publishedAt`,
`publicationSlug`, `postSlug`, `assetId`, `assetResolutionStatus`, and `asset`.
## Migrating from V1 to V2
1. **Switch URLs** — `/api/v1/stock-picks` → `/api/v2/stock-picks` and
`/api/v1/stock-picks/quote` → `/api/v2/stock-picks/quote`. Single-day
callers can keep passing `date=YYYY-MM-DD` unchanged.
2. **Authenticate** — if the caller has a PRO or EXPERT plan (Bearer API key,
OAuth, or JWT), in-window reads become free, no quote or payment needed. The
paid path for everyone else stays quote → confirm → pay.
3. **Adapt the response** — `items[]` becomes `picks[]`, `dateUsed` /
`startDate` / `endDate` become `meta` + a `date` on each pick, and the item
fields change:
| V1 field | V2 field |
| - | - |
| `items[]` | `picks[]` |
| `dateUsed` / `startDate` / `endDate` | `meta.appliedRange`, plus `date` per pick (`meta.asOf` is the response timestamp) |
| `authorConviction` | `conviction` |
| `articleUrl` | Drip sellable URL when a post is attributed |
| `tickerExchange`, `instrumentType` | Still returned; prefer `asset` for resolved identity |
| `activePick`, `articleTitle`, `postSlug` | Not returned; use `articleUrl` for the source |
| `assetId`, `assetResolutionStatus`, `asset` | Still returned |
| — | `publicationTitle`, optional `prices` (`entry` / `current` / `returnPct` / `currency`) |
4. **Pagination** — for ranges use `limitDays` + `cursor`; the response's
`pagination.nextCursor` continues older. Previously impossible beyond one day.
5. **Errors** — keep treating `404` as "no picks, do not pay". New: `403` for an
explicit out-of-window `date`, `429` for an exhausted API-key allowance.
6. **MCP** — prefer `quote_stock_picks_v2` / `list_stock_picks_v2`
(`confirmSpend: true` on the paid path only). The V1 tools
(`quote_stock_picks` / `list_stock_picks`) remain available.
## Hosted MCP
The four stock-picks tools map 1:1 to these routes:
| MCP tool | HTTP route | Paid? |
| - | - | - |
| `quote_stock_picks_v2` | `GET /api/v2/stock-picks/quote` | Free, no auth |
| `list_stock_picks_v2` | `GET /api/v2/stock-picks` | OAuth/API key required; subscribers free, others spend credits (`confirmSpend: true`) |
| `quote_stock_picks` | `GET /api/v1/stock-picks/quote` | Free, no auth |
| `list_stock_picks` | `GET /api/v1/stock-picks` | Credits (`confirmSpend: true`) |
Use V2 explicitly (`list_stock_picks_v2`). Both list tools require an API key or
OAuth token with `mcp:unlock`; anonymous wallet payments use HTTP instead. On
the paid path, always call the
matching quote tool first, show `amountUsd` as `$X.XX`, confirm with the user,
then call with `confirmSpend: true`.
# Top-selling
Source: https://docs.dripstack.com/top-selling
Most purchased posts and highest-earning publications. Free post cards, not summaries.
Use these only when the user asks for **popular, top-selling, or
most-purchased** items. They are not a substitute for
[topic search](/search) or [entity search](/entity-search/ticker).
Free, no auth. Post cards include `priceCents`; the `synthesizedSummary` still
comes from the [paid publication-post route](/concepts/payment-flow).
MCP: `list_top_selling_posts`, `list_top_selling_publications`.
`limit` is 1-100 on both routes (default 10).
## Posts
`GET /api/v1/posts/top-selling` ranks posts by purchase count, then earnings.
It only lists posts with ready synthesized summaries from enabled publications.
```bash theme={null}
curl "https://dripstack.com/api/v1/posts/top-selling?limit=10"
```
```json theme={null}
{
"items": [
{
"publicationSlug": "stratechery",
"slug": "the-ai-infrastructure-boom",
"title": "The AI Infrastructure Boom",
"subtitle": "Why hyperscalers are spending billions on GPU clusters",
"publishedAt": "2026-06-14T12:00:00.000Z",
"priceCents": 50,
"isPodcast": false,
"purchaseCount": 42,
"totalAmountSoldUsd": "21.00"
}
]
}
```
Present each item as `{title} ({publicationSlug}, YYYY-MM-DD) — $X.XX` when
`priceCents` is known. Keep `publicationSlug` + `slug` for the paid fetch.
## Publications
`GET /api/v1/publications/top-selling` ranks publications by creator
earnings, then purchase count.
```bash theme={null}
curl "https://dripstack.com/api/v1/publications/top-selling?limit=10"
```
```json theme={null}
{
"totals": {
"articlePurchaseCount": 1200,
"totalAmountSoldUsd": "640.00"
},
"publications": [
{
"slug": "stratechery",
"title": "Stratechery",
"description": "Analysis of the strategy and business of technology.",
"siteUrl": "https://stratechery.com",
"articlePurchaseCount": 80,
"purchasedArticleCount": 12,
"totalAmountSoldUsd": "40.00"
}
]
}
```
`articlePurchaseCount` is completed purchases; `purchasedArticleCount` is
distinct posts purchased. Disabled publications are excluded. `totals` covers
all enabled publications, including those beyond the requested `limit`.
After the user chooses a publication, call
[GET /api/v1/publications/](/publications) then unlock selected posts
as usual.
# Unlocks
Source: https://docs.dripstack.com/unlocks
Posts this account already paid to unlock. Metadata only — re-read the summary on the paid post route.
`GET /api/v1/me/unlocks` lists **lifetime unlocks** for the Drip user identified
by the API key or MCP OAuth token. Keys and tokens for the same user share this
list. Wallet and MPP unlocks belong to their payment identities and are not
included. Use it to answer "what has this account already bought?"
Requires `Authorization: Bearer pk_drip_…` or an MCP OAuth access token with
`mcp:unlock`. Session JWTs are rejected (`401`).
MCP: `list_unlocked_posts`.
This route does **not** return `synthesizedSummary`. Re-read with
`GET /api/v1/publications/{publicationSlug}/{postSlug}` (or MCP
`unlock_post`) — free after the first unlock for this Drip user. See
[Payment Flow](/concepts/payment-flow).
## List
```bash theme={null}
curl -H "Authorization: Bearer pk_drip_…" \
"https://dripstack.com/api/v1/me/unlocks?limit=20"
```
Cursor-paginated, newest first. Optional `limit` (1-50, default 20) and
`cursor` (pass the previous `nextCursor`). `nextCursor` is `null` when
exhausted. A bad `limit` returns `400` with field `issues`; an unknown
`cursor` returns `400` with `error: "Invalid cursor."`. Both include
`code: "bad_request"` and `hint`. See [Errors & Retries](/concepts/errors-retries).
```json theme={null}
{
"items": [
{
"id": "punl_01",
"publicationSlug": "stratechery",
"publicationName": "Stratechery",
"postSlug": "the-ai-infrastructure-boom",
"title": "The AI Infrastructure Boom",
"subtitle": "Why hyperscalers are spending billions on GPU clusters",
"author": "Ben Thompson",
"url": "https://stratechery.com/p/the-ai-infrastructure-boom",
"publishedAt": "2026-06-14T12:00:00.000Z",
"unlockedAt": "2026-06-15T10:30:00.000Z",
"isPodcast": false,
"amountUsd": 0.5
}
],
"nextCursor": null
}
```
`amountUsd` is the credits charged on first unlock, or `null` when no spend
row exists. `isPodcast` is true for episodes.
To unlock a **new** post, confirm `$X.XX` from discovery `priceCents`, then
call the paid publication-post route (HTTP) or `unlock_post` with
`confirmSpend: true` (MCP). MCP re-reads of an already-unlocked post do not
require `confirmSpend`.