Quickstart
- 1
Create an account
Register, then open the developer dashboard.
- 2
Create and fund a key
Copy the key once and add prepaid crypto credit.
- 3
Send a request
Search the corpus or retrieve a post, topic, or profile by ID.
Authentication
Send your API key in the Authorization header. Keys begin with ts_live_, are displayed once, and can be revoked immediately from your dashboard.
Authorization: Bearer ts_live_your_keyThe X-API-Key header is also supported. Never put a secret key in browser-delivered application code or a public repository.
Optional IP restrictions
Each key can be limited to individual IPv4 or IPv6 addresses and CIDR ranges, such as 203.0.113.10, 198.51.100.0/24, or 2001:db8::/32. Manage the allowlist from the developer dashboard. Requests from other addresses receive HTTP 403 before billing, with sourceIp showing the address TalkSearch detected.
Key expiration
Choose no expiration or a lifetime of 7, 30, 90, 180, or 365 days. An expired key receives HTTP 401 before billing. You can renew an expired key or change its expiration from the dashboard without replacing the secret.
/api/v1/searchSearch indexed posts
Returns ranked post-level matches from the indexed Bitcointalk corpus. Search applies language-specific dictionaries, hybrid lexical/vector ranking, duplicate suppression, and quality filtering.
/api/v1/images/searchSearch cached images
Find images through the text and metadata of the posts that contain them. Results are deduplicated by content and use stable cdn.talksearch.io URLs. Known forum smileys and high-confidence NSFW images are excluded by default.
| Name | Type | Required | Description |
|---|---|---|---|
q | string | Yes | Search query. Must contain between 1 and 512 characters. |
lang | string | No | Language index to search, such as en, de, fr, or pt-BR. |
freshness | string | No | Set to 1 to prefer newer posts. Omit it to use automatic freshness intent detection. |
include_low_quality | string | No | Set to 1 to include replies normally removed by TalkSearch quality and spam filtering. |
size | integer | No | Maximum unique images to return, from 1 to 50. Defaults to 24. |
hide_nsfw | string | No | High-confidence NSFW images are hidden by default. Set to 0 to include them. |
Retrieve corpus resources by ID
Use the numeric IDs from Bitcointalk URLs or TalkSearch results. A missing resource returns HTTP 404 and costs no credit.
Post by ID
/api/v1/posts/{id}Returns one indexed post with rendered HTML, author, board, topic, date, and merit observations.
Example ID: 34538660
Topic by ID
/api/v1/topics/{id}Returns topic metadata plus the complete first post and a summary of the latest indexed post.
Example ID: 3309245
Profile by ID
/api/v1/profiles/{id}Returns corpus-derived profile activity and recent posts for a Bitcointalk user ID.
Example ID: 1978649
Page through topic or profile posts
Use these collection endpoints to retrieve full posts in chronological order. They read the indexed corpus, not a new web scrape, and do not apply relevance, language, spam or diversity filtering. You do not need to guess or walk post IDs.
Posts in a topic
GET /api/v1/topics/{id}/postsChronologically page through full indexed posts in a topic, optionally restricted to one author.
Posts by a profile
GET /api/v1/profiles/{id}/postsChronologically page through full indexed posts by an author, optionally restricted to one topic.
Snapshot consistency: the first request freezes a point-in-time view. Legacy duplicates are resolved to one deterministic canonical document per post, independently of the current filters. New posts and updates appear only when you start a new request without a cursor. No exact or approximate total is returned.
Continuation: send the returned next_cursor unchanged. A cursor-only request inherits the initial filters, order and limit. You may repeat identical options, but changed, empty, repeated or unknown options are rejected with HTTP 400.
Do not stop on an empty page: a bounded duplicate scan may return fewer posts, or no posts, with a continuation. Keep going until next_cursor is null. A topic or profile with no indexed posts returns HTTP 200 with an empty list.
Expiry: cursors expire after five idle minutes and the snapshot lasts at most one hour. HTTP 410 means start a new snapshot; a tampered or mismatched cursor returns 400. These errors and upstream failures are not charged. Each successful page, including an empty terminal page, costs one credit.
| Name | Type | Description |
|---|---|---|
limit | integer | Maximum full posts per page (default 50). A bounded duplicate scan can return fewer or zero posts while next_cursor is still present. |
order | string | Chronological order; asc (oldest first) is the default. Ties use a stable post-ID order. |
date_from | string | Inclusive posting-time boundary. Exact YYYY-MM-DD means UTC midnight; alternatively use RFC3339 with an explicit timezone and at most millisecond precision. |
date_to | string | Exclusive posting-time boundary, using the same date syntax. For all of September 9 UTC, use date_from=2026-09-09 and date_to=2026-09-10. |
board_id | integer | Restrict to one Bitcointalk board ID; supported on both collection endpoints. |
author_uid | integer | Topic posts only: restrict the topic to one author’s numeric Bitcointalk user ID. |
topic_id | integer | Profile posts only: restrict the author’s posts to one topic ID. |
cursor | string | Opaque signed continuation token from next_cursor. Send it unchanged. Cursor-only requests inherit the original filters, order and limit; explicitly repeated options must be identical. Never construct a cursor or increment post IDs. |
Dates must be exact YYYY-MM-DD (UTC midnight) or RFC3339 timestamps with a timezone and no more than three fractional-second digits. date_from is inclusive; date_to is exclusive. Scope and filter IDs must be positive safe integers.
Python: topic posts from September 9, 2026, oldest first
import os
import requests
endpoint = "https://talksearch.io/api/v1/topics/5480200/posts"
headers = {"Authorization": "Bearer " + os.environ["TALKSEARCH_API_KEY"]}
params = {"date_from": "2026-09-09", "order": "asc", "limit": 50}
while True:
response = requests.get(endpoint, headers=headers, params=params, timeout=60)
response.raise_for_status() # 410: explicitly start a new snapshot if needed
page = response.json()
for post in page["data"]:
print(post["post_id"], post["posted_at"], post["content_html"])
cursor = page["next_cursor"]
if cursor is None:
break
# A short or empty page can still have a continuation. Do not increment IDs.
params = {"cursor": cursor} # Inherits all initial options; one credit/page.Post-search parameters
| Name | Type | Required | Description |
|---|---|---|---|
q | string | Yes | Search query. Must contain between 1 and 512 characters. |
lang | string | No | Language index to search, such as en, de, fr, or pt-BR. |
freshness | string | No | Set to 1 to prefer newer posts. Omit it to use automatic freshness intent detection. |
include_low_quality | string | No | Set to 1 to include replies normally removed by TalkSearch quality and spam filtering. |
Request examples
Use an environment variable or server-side secret manager for production keys.
curl 'https://talksearch.io/api/v1/search?q=taproot+fee+estimation&lang=en' \
-H 'Authorization: Bearer ts_live_your_key'Successful responses
Every response identifies its resource shape. The OpenAPI schema contains complete field definitions for code generation and validation.
Post search response
{
"query": "taproot fee estimation",
"corrected_query": null,
"lang": "en",
"board_scope": "strict-language-boards-v1",
"index": "talksearch_posts_v3_en",
"did_you_mean": null,
"hybrid": true,
"freshness": false,
"answer_seeking": true,
"total": 127,
"hits": [
{
"post_id": 64551288,
"topic_id": 5500892,
"title": "When Taproot?",
"topic_title": "When Taproot?",
"post_title": "Re: When Taproot?",
"content": "Example matching Bitcointalk post content.",
"author": "ExampleUser",
"author_uid": 3534730,
"date": "2024-09-20T01:58:23.000Z",
"board_id": 1,
"board_name": "Bitcoin Discussion",
"lang": "en",
"score": 0.822709,
"spam_score": 0,
"ai_score": 0,
"health_score": 1,
"rank_source": "hybrid",
"ranking_model_version": "relevance-authority-v5",
"search_index": "talksearch_posts_v3_en"
}
]
}Image search response
{
"object": "image_search",
"query": "hardware wallet",
"corrected_query": null,
"lang": "en",
"board_scope": "strict-language-boards-v1",
"hide_nsfw": true,
"post_matches_considered": 50,
"total": 1,
"images": [
{
"object": "image",
"sha256": "53e2d1c2be8f2a0c87efbd85c73915b58344fd9a7f40b6eeb734f4014b5d0f07",
"url": "https://cdn.talksearch.io/media/images/53e2d1c2be8f2a0c87efbd85c73915b58344fd9a7f40b6eeb734f4014b5d0f07.avif",
"mime_type": "image/avif",
"bytes": 48231,
"nsfw_score": 0.01,
"post": {
"post_id": 64551288,
"topic_id": 5500892,
"title": "Hardware wallet comparison",
"author": {
"profile_id": 3534730,
"username": "ExampleUser",
"url": "https://bitcointalk.org/index.php?action=profile;u=3534730"
},
"board": {
"board_id": 37,
"name": "Hardware Wallets"
},
"language": "en",
"posted_at": "2024-09-20T01:58:23.000Z",
"url": "https://bitcointalk.org/index.php?topic=5500892.msg64551288#msg64551288",
"topic_url": "https://bitcointalk.org/index.php?topic=5500892.0"
}
}
]
}Post by ID response
{
"object": "post",
"post_id": 34538660,
"topic_id": 3309245,
"post_number": 1,
"is_op": true,
"title": "Forget about exchanger search! Use BestChange!",
"author": {
"profile_id": 1978649,
"username": "Best.Change",
"url": "https://bitcointalk.org/index.php?action=profile;u=1978649"
},
"board": {
"board_id": 84,
"name": "Service Announcements"
},
"language": "en",
"posted_at": "2018-04-12T00:00:00.000Z",
"url": "https://bitcointalk.org/index.php?topic=3309245.msg34538660#msg34538660",
"topic_url": "https://bitcointalk.org/index.php?topic=3309245.0",
"content_html": "<p>BestChange.com helps compare exchangers.</p>",
"indexed_at": "2026-08-29T12:00:00.000Z",
"merit": {
"total": 0,
"distinct_senders": 0,
"transactions": 0,
"observed_at": null
}
}Topic by ID response
{
"object": "topic",
"topic_id": 3309245,
"title": "Forget about exchanger search! Use BestChange!",
"board": {
"board_id": 84,
"name": "Service Announcements"
},
"language": "en",
"created_at": "2018-04-12T00:00:00.000Z",
"last_post_at": "2026-08-29T00:00:00.000Z",
"post_count": 2400,
"page_count": 120,
"views": {
"observed": 100000,
"observed_at": "2026-08-29T00:00:00.000Z"
},
"merit": {
"total": 400,
"distinct_senders": 120,
"transactions": 200,
"observed_at": "2026-08-29T00:00:00.000Z"
},
"url": "https://bitcointalk.org/index.php?topic=3309245.0",
"first_post": {
"object": "post",
"post_id": 34538660,
"topic_id": 3309245,
"post_number": 1,
"is_op": true,
"title": "Forget about exchanger search! Use BestChange!",
"author": {
"profile_id": 1978649,
"username": "Best.Change",
"url": "https://bitcointalk.org/index.php?action=profile;u=1978649"
},
"board": {
"board_id": 84,
"name": "Service Announcements"
},
"language": "en",
"posted_at": "2018-04-12T00:00:00.000Z",
"url": "https://bitcointalk.org/index.php?topic=3309245.msg34538660#msg34538660",
"topic_url": "https://bitcointalk.org/index.php?topic=3309245.0",
"content_html": "<p>BestChange.com helps compare exchangers.</p>",
"indexed_at": "2026-08-29T12:00:00.000Z",
"merit": {
"total": 0,
"distinct_senders": 0,
"transactions": 0,
"observed_at": null
}
},
"latest_post": {
"post_id": 67000000,
"topic_id": 3309245,
"post_number": 2400,
"is_op": false,
"title": "Forget about exchanger search! Use BestChange!",
"author": {
"profile_id": 1978649,
"username": "Best.Change",
"url": "https://bitcointalk.org/index.php?action=profile;u=1978649"
},
"board": {
"board_id": 84,
"name": "Service Announcements"
},
"language": "en",
"posted_at": "2026-08-29T00:00:00.000Z",
"url": "https://bitcointalk.org/index.php?topic=3309245.msg67000000#msg67000000",
"topic_url": "https://bitcointalk.org/index.php?topic=3309245.0"
}
}Profile by ID response
{
"object": "profile",
"profile_id": 1978649,
"username": "Best.Change",
"url": "https://bitcointalk.org/index.php?action=profile;u=1978649",
"corpus": {
"post_count": 1200,
"topic_count": 18,
"first_post_at": "2017-11-01T00:00:00.000Z",
"last_post_at": "2026-08-29T00:00:00.000Z",
"derived_from": "distinct indexed posts"
},
"recent_posts": [
{
"post_id": 67000000,
"topic_id": 3309245,
"post_number": 2400,
"is_op": false,
"title": "Forget about exchanger search! Use BestChange!",
"author": {
"profile_id": 1978649,
"username": "Best.Change",
"url": "https://bitcointalk.org/index.php?action=profile;u=1978649"
},
"board": {
"board_id": 84,
"name": "Service Announcements"
},
"language": "en",
"posted_at": "2026-08-29T00:00:00.000Z",
"url": "https://bitcointalk.org/index.php?topic=3309245.msg67000000#msg67000000",
"topic_url": "https://bitcointalk.org/index.php?topic=3309245.0"
}
]
}Posts in a topic response (illustrative cursor)
{
"object": "post_list",
"scope": {
"type": "topic",
"id": 5480200
},
"order": "asc",
"limit": 50,
"filters": {
"date_from": "2026-09-09T00:00:00.000Z",
"date_to": null,
"board_id": null,
"author_uid": null,
"topic_id": null
},
"snapshot_at": "2026-09-26T12:00:00.000Z",
"cursor_expires_at": "2026-09-26T12:05:00.000Z",
"has_more": true,
"next_cursor": "opaque_payload.opaque_signature",
"data": [
{
"object": "post",
"post_id": 67000001,
"topic_id": 5480200,
"post_number": 2,
"is_op": false,
"title": "Example topic",
"author": {
"profile_id": 1978649,
"username": "Best.Change",
"url": "https://bitcointalk.org/index.php?action=profile;u=1978649"
},
"board": {
"board_id": 84,
"name": "Service Announcements"
},
"language": "en",
"posted_at": "2026-09-09T12:30:00.000Z",
"url": "https://bitcointalk.org/index.php?topic=5480200.msg67000001#msg67000001",
"topic_url": "https://bitcointalk.org/index.php?topic=5480200.0",
"content_html": "<p>Illustrative indexed post content.</p>",
"indexed_at": "2026-09-26T11:59:00.000Z",
"merit": {
"total": 0,
"distinct_senders": 0,
"transactions": 0,
"observed_at": null
}
}
]
}Posts by a profile response (illustrative cursor)
{
"object": "post_list",
"scope": {
"type": "profile",
"id": 1978649
},
"order": "asc",
"limit": 50,
"filters": {
"date_from": "2026-09-09T00:00:00.000Z",
"date_to": null,
"board_id": null,
"author_uid": null,
"topic_id": null
},
"snapshot_at": "2026-09-26T12:00:00.000Z",
"cursor_expires_at": "2026-09-26T12:05:00.000Z",
"has_more": true,
"next_cursor": "opaque_payload.opaque_signature",
"data": [
{
"object": "post",
"post_id": 67000001,
"topic_id": 5480200,
"post_number": 2,
"is_op": false,
"title": "Example topic",
"author": {
"profile_id": 1978649,
"username": "Best.Change",
"url": "https://bitcointalk.org/index.php?action=profile;u=1978649"
},
"board": {
"board_id": 84,
"name": "Service Announcements"
},
"language": "en",
"posted_at": "2026-09-09T12:30:00.000Z",
"url": "https://bitcointalk.org/index.php?topic=5480200.msg67000001#msg67000001",
"topic_url": "https://bitcointalk.org/index.php?topic=5480200.0",
"content_html": "<p>Illustrative indexed post content.</p>",
"indexed_at": "2026-09-26T11:59:00.000Z",
"merit": {
"total": 0,
"distinct_senders": 0,
"transactions": 0,
"observed_at": null
}
}
]
}Try it
Send a real request without leaving the documentation. Your key stays in this page’s memory and is sent only to the same-origin TalkSearch API.
Choose an operation, enter a revocable API key, and inspect the live JSON response and metering headers.
Errors
| HTTP | Meaning | What to do |
|---|---|---|
| 400 | A query, resource ID, collection option, or cursor is invalid. Collection options cannot be unknown, repeated, empty, or different from the cursor’s original options. | Correct the request parameters. For a different collection scope or filter, start without a cursor. |
| 401 | The API key is missing, invalid, expired, or revoked. | Use an active key or renew an expired key from the developer dashboard. |
| 402 | The account has insufficient prepaid credits. | Top up the account before retrying. |
| 403 | The source IP is not allowed for this API key. | Add the returned sourceIp to the key allowlist, or send the request from an allowed address. |
| 404 | An individual resource lookup did not find the requested post, topic, or profile. A collection with no indexed posts instead returns 200 and an empty list. | Check the Bitcointalk ID. Not-found lookups are not charged. |
| 410 | A collection cursor or its indexed snapshot has expired. | Start a new collection request without a cursor. Expired requests are not charged. |
| 429 | The API-key rate limit was exceeded. | Wait until X-RateLimit-Reset, then retry with backoff. |
| 503 | The requested operation could not complete. | Retry later. The failed request is not charged. |
Metering and limits
One credit per success
A completed search, returned resource, or successful collection page charges one credit. This includes empty terminal collection pages. Invalid requests, not-found resources, expired cursors, and service failures are not charged.
120 requests per minute
The limit applies per API key. Use the X-RateLimit-* response headers to schedule retries.
Successful responses also return X-Request-Id, X-Credits-Charged, and X-Credits-Remaining.