Quickstart
Authenticate, verify your key with one cheap call, then make your first /research call and get a cited answer from live sources.
Prerequisites
Section titled “Prerequisites”- A programming environment (examples use curl, TypeScript, and Python)
- Basic knowledge of REST APIs
Create and Setup Your API Key
Before you can start using Tabstack API, you’ll need to create an API key and set it up in your environment.
1. Create Your API Key
- Visit the Tabstack Console
- Sign in to your account (or create one if you haven’t already)
- Navigate to the API Keys section and click the “Manage API Keys”
- Once you are on the API Keys page, Click “Create New API Key”
- Give your key a descriptive name (e.g., “Development”, “Production”) and click the “Create API Key”
- Copy the generated API key and store it securely
2. Set Up Environment Variable
For security and convenience, we recommend storing your API key as an environment variable rather than hardcoding it in your scripts.
macOS/Linux
# Add to your shell profile (~/.bashrc, ~/.zshrc, or ~/.bash_profile)export TABSTACK_API_KEY="your_api_key_here"
# Or set it temporarily for the current sessionexport TABSTACK_API_KEY="your_api_key_here"
# Reload your shell or run:source ~/.bashrc # or ~/.zshrcWindows (Command Prompt)
# Set temporarily for current sessionset TABSTACK_API_KEY=your_api_key_here
# Set permanently (requires restart)setx TABSTACK_API_KEY "your_api_key_here"Windows (PowerShell)
# Set temporarily for current session$env:TABSTACK_API_KEY = "your_api_key_here"
# Set permanently for current user[Environment]::SetEnvironmentVariable("TABSTACK_API_KEY", "your_api_key_here", "User")3. Verify Your Setup
Test that your environment variable is set correctly:
macOS/Linux/Windows (Git Bash):
echo $TABSTACK_API_KEYWindows (Command Prompt):
echo %TABSTACK_API_KEY%Windows (PowerShell):
echo $env:TABSTACK_API_KEYYou should see your API key printed in the terminal.
Install an SDK
Section titled “Install an SDK”Every endpoint works over plain HTTP, so curl is enough to get a first response. For anything beyond that, install the SDK for your language:
npm install @tabstack/sdkpip install tabstackFor package manager alternatives (yarn, pnpm, bun, uv, poetry, pipenv), see the TypeScript SDK Quickstart or Python SDK Quickstart.
Authentication
Section titled “Authentication”Tabstack API uses API key authentication. Include your API key in the Authorization header:
Authorization: Bearer $TABSTACK_API_KEYNow that you have your environment variable set up, you can use $TABSTACK_API_KEY (or %TABSTACK_API_KEY% on Windows Command Prompt) in your curl commands.
Setup check
Section titled “Setup check”Before the first real call, prove the key works. /extract/markdown is the cheapest and most deterministic endpoint: one URL in, clean text out, 10 credits. It is a setup check, not the thing you came for.
curl -X POST "https://api.tabstack.ai/v1/extract/markdown" \ -H "Authorization: Bearer $TABSTACK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com" }'import Tabstack from "@tabstack/sdk";
const client = new Tabstack({ apiKey: process.env.TABSTACK_API_KEY!,});
try { const result = await client.extract.markdown({ url: "https://example.com", }); console.log(result.content);} catch (error) { console.error("Error:", error);}import osfrom tabstack import Tabstack
with Tabstack(api_key=os.getenv('TABSTACK_API_KEY')) as client: try: result = client.extract.markdown(url='https://example.com') print(result.content) except Exception as error: print(f'Error: {error}')Response (raw HTTP body; the SDKs return the same fields as a typed object, so result.content holds the markdown):
{ "url": "https://example.com", "content": "---\ntitle: Example Domain\ndescription: Example Domain\nurl: https://example.com\ntype: website\n---\n\n# Example Domain\n\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\n\n[More information...](https://www.iana.org/domains/example)"}Your first research call
Section titled “Your first research call”/research is the call that shows what Tabstack does. You send a question and get back a synthesized answer with the sources it cited. Query planning, source selection, page fetching, gap checks, and citation happen inside the call, so your model never has to run a search loop.
The endpoint always streams over Server-Sent Events. Progress events arrive while the research runs, and a final complete event carries the report.
curl -N -X POST "https://api.tabstack.ai/v1/research" \ -H "Authorization: Bearer $TABSTACK_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "query": "What are the main approaches to browser automation for AI agents?", "mode": "fast" }'import Tabstack from "@tabstack/sdk";
const client = new Tabstack({ apiKey: process.env.TABSTACK_API_KEY!,});
const stream = await client.agent.research({ query: "What are the main approaches to browser automation for AI agents?", mode: "fast",});
for await (const event of stream) { if (event.event === "error") { throw new Error(event.data.error?.message ?? "Research failed"); } if (event.event === "complete") { console.log(event.data.report);
for (const page of event.data.metadata.citedPages ?? []) { console.log(`- ${page.title ?? "(untitled)"}: ${page.url}`); } }}import osfrom tabstack import Tabstack
with Tabstack(api_key=os.getenv('TABSTACK_API_KEY')) as client: for event in client.agent.research( query='What are the main approaches to browser automation for AI agents?', mode='fast', ): if event.event == 'error': raise RuntimeError(event.data.error.message if event.data.error else 'Research failed') if event.event == 'complete': print(event.data.report)
for page in event.data.metadata.cited_pages or []: print(f"- {page.title or '(untitled)'}: {page.url}")Response. Progress events stream first, then complete carries the report and its sources:
{ "report": "There are three main approaches...", "metadata": { "mode": "fast", "totalPagesAnalyzed": 9, "citedPages": [ { "id": "src-1", "url": "https://example.com/browser-automation", "title": "Browser Automation Approaches", "claims": [] } ] }}That citedPages array is the part your users can check: each entry is a source the report cites. claims, the statements a source supports, is populated in balanced mode only; in fast mode it comes back as an empty array.
Extract matching JSON
Section titled “Extract matching JSON”The other call you will reach for constantly is /extract/json. You point it at a page and define a schema, and you get back data in that shape.
curl -X POST "https://api.tabstack.ai/v1/extract/json" \ -H "Authorization: Bearer $TABSTACK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://news.ycombinator.com", "json_schema": { "type": "object", "properties": { "stories": { "type": "array", "description": "Front page stories", "items": { "type": "object", "properties": { "title": { "type": "string", "description": "Story headline" }, "points": { "type": "number", "description": "Score in points" } } } } } } }'import Tabstack from "@tabstack/sdk";
const client = new Tabstack({ apiKey: process.env.TABSTACK_API_KEY!,});
try { const result = await client.extract.json({ url: "https://news.ycombinator.com", json_schema: { type: "object", properties: { stories: { type: "array", description: "Front page stories", items: { type: "object", properties: { title: { type: "string", description: "Story headline" }, points: { type: "number", description: "Score in points" }, }, }, }, }, }, }); console.log(result);} catch (error) { console.error("Error:", error);}import osfrom tabstack import Tabstack
with Tabstack(api_key=os.getenv('TABSTACK_API_KEY')) as client: try: result = client.extract.json( url='https://news.ycombinator.com', json_schema={ 'type': 'object', 'properties': { 'stories': { 'type': 'array', 'description': 'Front page stories', 'items': { 'type': 'object', 'properties': { 'title': {'type': 'string', 'description': 'Story headline'}, 'points': {'type': 'number', 'description': 'Score in points'}, }, }, }, }, }, ) print(result) except Exception as error: print(f'Error: {error}')The parameter is json_schema, not schema. Those description fields are not decoration: they tell the extractor what to look for, and they are the single biggest factor in extraction quality. See Schema Design before you write a real one, including what a field returns when it can’t be filled.
Next Steps
Section titled “Next Steps”Now that you’re up and running:
- Go deeper on Research: the Research guide covers modes, the full event stream, and how to handle long-running calls
- Understand the distinction: Search versus research maps which steps Tabstack runs inside the call and which ones a search API leaves to your model
- Design your schemas: Schema Design is the difference between JSON that matches and JSON that disappoints
- Go deeper on your SDK: Python SDK Quickstart or TypeScript SDK Quickstart
- Explore Examples: Check out our Price Monitor Example to see how to build a real-world application
- Plan your capacity: Rate Limits covers requests per minute per plan, and Pricing covers what each endpoint costs in credits
- API Reference: Review the API Reference for detailed endpoint documentation
Need Help?
Section titled “Need Help?”- Documentation: docs.tabstack.ai
- Support: support@tabstack.ai