Search Documents
curl --request GET \
--url https://api.example.com/v1/documents/searchimport requests
url = "https://api.example.com/v1/documents/search"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/documents/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/v1/documents/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/documents/search"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v1/documents/search")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/documents/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "<string>",
"ticker": "<string>",
"company_name": "<string>",
"doc_type": "<string>",
"filing_date": "<string>",
"section_type": "<string>",
"section_title": "<string>",
"snippet": "<string>",
"relevance_score": 123,
"semantic_score": 123,
"content": "<string>"
}
]
}Documents
Search Documents
Search SEC filings with keyword, semantic, or hybrid modes
GET
/
v1
/
documents
/
search
Search Documents
curl --request GET \
--url https://api.example.com/v1/documents/searchimport requests
url = "https://api.example.com/v1/documents/search"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/documents/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/v1/documents/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/documents/search"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v1/documents/search")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/documents/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "<string>",
"ticker": "<string>",
"company_name": "<string>",
"doc_type": "<string>",
"filing_date": "<string>",
"section_type": "<string>",
"section_title": "<string>",
"snippet": "<string>",
"relevance_score": 123,
"semantic_score": 123,
"content": "<string>"
}
]
}Overview
Search across SEC filing sections including debt footnotes, credit agreements, indentures, and MD&A sections. Find covenant language, guarantor lists, and specific debt terms. Supports three search modes:- Keyword (default) — PostgreSQL full-text search with relevance ranking
- Semantic — Vector similarity search using Gemini embeddings (finds conceptually similar content even without keyword matches)
- Hybrid — Combines keyword and semantic results via Reciprocal Rank Fusion for the best of both
Request
string
required
Search query. For keyword/hybrid mode, uses full-text search syntax. For semantic mode, use natural language.Example:
maintenance covenant, subordinated, can they pay dividendsstring
default:"keyword"
Search mode. One of:
keyword— Full-text search with relevance ranking (default)semantic— Vector similarity search using AI embeddingshybrid— Combines keyword + semantic via Reciprocal Rank Fusion
string
Comma-separated company tickers.Example:
RIG,CHTRstring
Filing type:
10-K, 10-Q, 8-Kstring
Section type to search. See section types below.
string
Minimum filing date (YYYY-MM-DD).
string
Maximum filing date (YYYY-MM-DD).
string
Fields to return.Example:
ticker,section_type,snippet,relevance_score,semantic_scorestring
default:"-relevance"
Sort order:
-relevance, -filing_date, filing_dateinteger
default:"50"
Results per page. Maximum 100.
integer
default:"0"
Pagination offset.
Section Types
| Type | Description | Source |
|---|---|---|
exhibit_21 | Subsidiary list | 10-K Exhibit 21 |
debt_footnote | Long-term debt details | 10-K/10-Q Notes |
mda_liquidity | Liquidity discussion | MD&A section |
credit_agreement | Full credit facility docs | 8-K Exhibit 10 |
indenture | Bond indentures | 8-K Exhibit 4 |
guarantor_list | Guarantor subsidiaries | Notes |
covenants | Financial covenants | Notes/Exhibits |
Response
array
Array of matching document sections.
Show properties
Show properties
string
Section ID.
string
Company ticker.
string
Company name.
string
Filing type.
string
Filing date.
string
Section type.
string
Section title.
string
Highlighted snippet with matching terms in
<b> tags.number
Search relevance score (0-1). Available in keyword and hybrid modes.
number
Cosine similarity score (0-1). Available in semantic and hybrid modes.
string
Full section content (if requested).
Examples
Search Debt Footnotes
curl "https://api.debtstack.ai/v1/documents/search?q=subordinated§ion_type=debt_footnote&fields=ticker,section_type,snippet,relevance_score" \
-H "X-API-Key: ds_xxxxx"
import requests
response = requests.get(
"https://api.debtstack.ai/v1/documents/search",
params={
"q": "subordinated",
"section_type": "debt_footnote",
"fields": "ticker,section_type,snippet,relevance_score"
},
headers={"X-API-Key": "ds_xxxxx"}
)
for doc in response.json()["data"]:
print(f"{doc['ticker']}: {doc['snippet'][:100]}...")
Response
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"ticker": "RIG",
"company_name": "Transocean Ltd.",
"doc_type": "10-K",
"filing_date": "2025-02-15",
"section_type": "debt_footnote",
"section_title": "Note 9 - Long-Term Debt",
"snippet": "...senior <b>subordinated</b> notes due 2028 are structurally <b>subordinated</b> to all obligations of our operating subsidiaries...",
"relevance_score": 0.85
},
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"ticker": "CHTR",
"company_name": "Charter Communications, Inc.",
"doc_type": "10-K",
"filing_date": "2025-02-23",
"section_type": "debt_footnote",
"section_title": "Note 8 - Long-Term Debt",
"snippet": "...holdco notes are structurally <b>subordinated</b> to all obligations of CCO Holdings...",
"relevance_score": 0.78
}
],
"meta": {
"query": "subordinated",
"mode": "keyword",
"total": 42,
"limit": 50,
"offset": 0
}
}
Search Credit Agreements
Find maintenance covenants:curl "https://api.debtstack.ai/v1/documents/search?q=maintenance%20covenant§ion_type=credit_agreement&ticker=CHTR" \
-H "X-API-Key: ds_xxxxx"
Search Indentures
Find events of default:curl "https://api.debtstack.ai/v1/documents/search?q=event%20of%20default§ion_type=indenture&limit=10" \
-H "X-API-Key: ds_xxxxx"
Semantic Search
Find conceptually similar content using natural language — no exact keyword match needed:curl "https://api.debtstack.ai/v1/documents/search?q=can%20they%20pay%20dividends&ticker=RIG&mode=semantic&fields=ticker,section_type,section_title,semantic_score" \
-H "X-API-Key: ds_xxxxx"
response = requests.get(
"https://api.debtstack.ai/v1/documents/search",
params={
"q": "can they pay dividends",
"ticker": "RIG",
"mode": "semantic",
"fields": "ticker,section_type,section_title,semantic_score"
},
headers={"X-API-Key": "ds_xxxxx"}
)
for doc in response.json()["data"]:
print(f"{doc['section_type']}: {doc['section_title']} (score: {doc['semantic_score']:.2f})")
{
"data": [
{
"ticker": "RIG",
"section_type": "indenture",
"section_title": "Limitation on Restricted Payments",
"semantic_score": 0.67
},
{
"ticker": "RIG",
"section_type": "indenture",
"section_title": "Covenants - Restricted Payments",
"semantic_score": 0.64
}
],
"meta": {
"query": "can they pay dividends",
"mode": "semantic",
"total": 15,
"limit": 50,
"offset": 0
}
}
Semantic search finds “Limitation on Restricted Payments” for the query “can they pay dividends” — even though none of the keywords match. This is the power of vector similarity search.
Hybrid Search
Combine keyword precision with semantic understanding:curl "https://api.debtstack.ai/v1/documents/search?q=restricted%20payment%20basket&ticker=CHTR&mode=hybrid&fields=ticker,section_type,relevance_score,semantic_score" \
-H "X-API-Key: ds_xxxxx"
Get Full Document Content
response = requests.get(
f"{BASE_URL}/documents/search",
params={
"q": "redemption",
"section_type": "indenture",
"ticker": "RIG",
"fields": "ticker,section_title,content", # Include full content
"limit": 1
},
headers={"X-API-Key": API_KEY}
)
doc = response.json()["data"][0]
print(f"Full content length: {len(doc['content'])} characters")
Use Cases
Find Covenant Details
def find_covenants(ticker):
"""Find all covenant mentions for a company."""
response = requests.get(
f"{BASE_URL}/documents/search",
params={
"q": "leverage ratio OR interest coverage",
"ticker": ticker,
"section_type": "covenants,credit_agreement",
"sort": "-relevance"
},
headers={"X-API-Key": API_KEY}
)
return response.json()["data"]
# Usage
covenants = find_covenants("CHTR")
for cov in covenants[:5]:
print(f"{cov['section_type']}: {cov['snippet'][:150]}...")
Search for Specific Terms
def search_filings(query, companies=None, section_type=None):
"""Search SEC filings for specific terms."""
params = {
"q": query,
"fields": "ticker,filing_date,section_type,snippet,relevance_score",
"sort": "-relevance",
"limit": 20
}
if companies:
params["ticker"] = ",".join(companies)
if section_type:
params["section_type"] = section_type
response = requests.get(
f"{BASE_URL}/documents/search",
params=params,
headers={"X-API-Key": API_KEY}
)
return response.json()["data"]
# Find change of control provisions
results = search_filings("change of control", section_type="indenture")
Monitor Filing Updates
from datetime import datetime, timedelta
def recent_filings(query, days=30):
"""Find matches in recent filings."""
since = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
response = requests.get(
f"{BASE_URL}/documents/search",
params={
"q": query,
"filed_after": since,
"sort": "-filing_date"
},
headers={"X-API-Key": API_KEY}
)
return response.json()["data"]
# Find recent mentions of refinancing
recent = recent_filings("refinancing OR amendment", days=90)
Search Modes
| Mode | Best For | How It Works |
|---|---|---|
keyword | Exact terms, legal language | PostgreSQL full-text search with ts_rank relevance scoring |
semantic | Natural language questions, conceptual search | Embeds query with Gemini, finds similar document chunks via cosine similarity (threshold 0.3) |
hybrid | Best overall results | Runs both keyword and semantic, combines via Reciprocal Rank Fusion (RRF) |
- Use
keywordwhen you know the exact terminology (e.g.,event of default,SOFR) - Use
semanticwhen asking questions in plain English (e.g.,can they pay dividends,what happens if they miss a payment) - Use
hybridwhen you want comprehensive results that catch both exact matches and conceptually related content
Notes
- Keyword mode uses PostgreSQL full-text search with relevance ranking
- Semantic mode uses 768-dimensional Gemini embeddings with cosine similarity
- Hybrid mode combines both via Reciprocal Rank Fusion (k=60)
- Snippets highlight matching terms with
<b>tags (keyword and hybrid modes) - Credit agreements and indentures can be large (up to 500K chars)
- Use
contentfield sparingly to avoid large responses - Credit cost: 3 credits per request

