# 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`.