Preview and unlock
See what a search would return, and what it would cost, before you pay for it.
Why preview
POST /api/v1/search/query charges for a search whether or not it turned out to be worth paying for. Preview removes that risk: it runs the same search pipeline, but returns teaser rows and an estimated price instead of billing you. You decide whether to pay only after seeing what's there.
POST /api/v1/search/preview: free. Runs the search, returns teaser rows plus aqueryIdand an estimated cost to unlock.POST /api/v1/search/unlock: pays for and returns some or all of those results in full.
POST /api/v1/search/query is unchanged. Preview is additive: use it when you want to inspect relevance before spending, and keep calling /api/v1/search/query directly wherever that fits your flow better.
One identifier runs through both calls: the same queryId a search already returns. There is no second id to learn, and it works the same way GET /api/v1/search/results/{queryId} already does: a preview is available for 7 days.
Preview works even at a zero credit balance, since it costs nothing. It's the right call to make when deciding whether to top up. Unlock is the paywall: it's the only one of the two that spends a quota slot, and it counts as the query.
Preview
POST /api/v1/search/preview
Takes the same request body as POST /api/v1/search/query (collection/collections, query, limit, filters, include_metadata). Every result comes back with locked: true, text holding a short teaser rather than the full chunk, and tokens/cost showing what unlocking that one row would cost. Locators (doi, pmid, pmcid, url) and full metadata are included in the free response, so you can judge relevance before paying for anything.
Preview consumes no quota and no trial query: it is unmetered on the billing side. It is rate limited per organization per hour; see Rate limits for the current default. Extra API keys on the same organization share one limit, they don't multiply it.
Example request
curl -X POST "https://api.redpine.ai/api/v1/search/preview" \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"collection": "my-collection",
"query": "What are the symptoms of diabetes?",
"limit": 10
}'preview takes the same filters as search, including the F builder from Filtering.
Example response
{
"queryId": "qry_a1b2c3d4e5f6",
"results": [
{
"id": "abc123",
"text": "Type 2 diabetes symptoms include increased...",
"metadata": {
"title": "Diabetes Overview",
"doi": "10.1234/example"
},
"collection": "my-collection",
"locked": true,
"tokens": 214,
"cost": "0.214000"
}
],
"costToUnlockRemaining": "0.214000",
"costCharged": null
}Unlock
POST /api/v1/search/unlock
Pays for previewed results and returns them in full.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
queryId | string | Yes | queryId from a previous POST /api/v1/search/preview |
resultIds | string[] | null | No | Results to unlock, by id. Omit (or pass null) to unlock every result from the preview |
Response fields
| Field | Type | Description |
|---|---|---|
queryId | string | Pass this to a later POST /api/v1/search/unlock call for the same preview |
results | array | The full result set, filtered through the unlock ledger: rows this call (or an earlier one) paid for come back in full, the rest still teased |
costToUnlockRemaining | string | Cost to unlock every result not yet unlocked |
costCharged | string | null | What this call charged, not a running total. Null on a preview (always free) and on an unlock whose entire delta was already unlocked |
filterWarnings | array | null | Advisory warnings for filter fields with no payload index; omitted when there are none. Same diagnostics POST /api/v1/search/query returns. See Search |
journalMetricExpansions | array | null | How each journal-metric filter condition resolved to ISSNs; omitted when no metric filter was used |
An unlock that buys something is the query: it spends one quota slot. A retried unlock (one whose resultIds were already paid for) charges nothing and burns no quota slot, so it's safe to retry.
Example request
curl -X POST "https://api.redpine.ai/api/v1/search/unlock" \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queryId": "qry_a1b2c3d4e5f6"
}'Two errors are specific to unlock and have their own SDK classes: 402 when the organisation cannot pay for the delta (InsufficientCredits, Go *InsufficientCreditsError) and 410 when the preview is past its 7-day window (Expired, Go *ExpiredError). Neither is retried.
Example response
{
"queryId": "qry_a1b2c3d4e5f6",
"results": [
{
"id": "abc123",
"text": "Type 2 diabetes symptoms include increased thirst, frequent urination, unexplained weight loss...",
"metadata": {
"title": "Diabetes Overview",
"doi": "10.1234/example"
},
"collection": "my-collection",
"locked": false,
"tokens": 214,
"cost": "0.214000"
}
],
"costToUnlockRemaining": "0.000000",
"costCharged": "0.214000"
}Partial unlock
Pass resultIds to buy some rows from a preview and leave the rest locked:
curl -X POST "https://api.redpine.ai/api/v1/search/unlock" \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queryId": "qry_a1b2c3d4e5f6",
"resultIds": ["abc123", "def456"]
}'Only the ids you pass are charged. Re-sending an id you already unlocked (in this call or an earlier one) costs nothing, since unlock charges the delta only: call it again later with more ids to unlock the rest of the same preview, or the same ids again with no risk of a duplicate charge.
costToUnlockRemaining is an estimate, summed per row. The amount actually charged by an unlock is computed per billing group, so the two can differ by a rounding fraction.
Two-call example
# 1. Preview for free -- see teasers and the price
curl -X POST "https://api.redpine.ai/api/v1/search/preview" \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"collection": "my-collection", "query": "What are the symptoms of diabetes?", "limit": 10}'
# 2. Unlock the results worth paying for
curl -X POST "https://api.redpine.ai/api/v1/search/unlock" \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"queryId": "qry_a1b2c3d4e5f6", "resultIds": ["abc123"]}'