# Balance
Source: https://docs.orthogonal.com/api-reference/balance
GET /v1/credits/balance
Check your credit balance
Returns the current credit balance for the authenticated API key.
## Authentication
Requires a valid API key via `Authorization: Bearer YOUR_API_KEY`.
* **User API keys** return the user's credit balance.
* **Organization API keys** return the organization's provider balance (revenue).
## Response
```json theme={null}
{
"balance": "$5.00"
}
```
### Response Fields
| Field | Type | Description |
| --------- | -------- | ------------------------ |
| `balance` | `string` | Formatted dollar balance |
## Example
```bash cURL theme={null}
curl 'https://api.orthogonal.com/v1/credits/balance' \
-H 'Authorization: Bearer YOUR_API_KEY'
```
```bash CLI theme={null}
orth balance
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/credits/balance', {
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`
}
});
const { balance } = await response.json();
console.log(`Balance: ${balance}`);
```
```python Python theme={null}
import requests
import os
response = requests.get(
'https://api.orthogonal.com/v1/credits/balance',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'}
)
balance = response.json()
print(f"Balance: {balance['balance']}")
```
## Check Sufficiency
Use `POST /v1/credits/check` to verify you have enough balance before making an API call:
```bash theme={null}
curl -X POST 'https://api.orthogonal.com/v1/credits/check' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"amountCents": 100}'
```
```json theme={null}
{
"sufficient": true,
"balanceCents": 500000,
"requiredCents": 100,
"shortfallCents": 0
}
```
# Get Details
Source: https://docs.orthogonal.com/api-reference/details
POST /v1/details
Get full parameter information for an endpoint
Get complete details about a specific API endpoint, including all parameters, types, and descriptions.
## Request
API slug from search results (e.g., "apollo", "linkup", "olostep")
Endpoint path (e.g., "/v1/people/match", "/v1/search")
## Response
```json theme={null}
{
"success": true,
"api": {
"name": "Apollo.io",
"slug": "apollo",
"description": "B2B lead enrichment and contact database",
"baseUrl": "https://api.apollo.io",
"verified": true
},
"endpoint": {
"path": "/v1/people/match",
"method": "POST",
"description": "Enrich a person by email, name, or LinkedIn URL",
"price": "$0.03",
"isPayable": true,
"docsUrl": "https://apolloio.github.io/apollo-api-docs",
"bodyType": "object",
"pathParams": [],
"queryParams": [],
"bodyParams": [
{
"name": "email",
"type": "string",
"required": false,
"description": "Email address to enrich"
},
{
"name": "first_name",
"type": "string",
"required": false,
"description": "First name of the person"
},
{
"name": "last_name",
"type": "string",
"required": false,
"description": "Last name of the person"
},
{
"name": "organization_name",
"type": "string",
"required": false,
"description": "Company name"
},
{
"name": "linkedin_url",
"type": "string",
"required": false,
"description": "LinkedIn profile URL"
}
]
},
"usage": {
"runApi": "POST /v1/run with {\"api\": \"apollo\", \"path\": \"/v1/people/match\", ...}",
"x402": "https://x402.orthogonal.com/apollo/v1/people/match"
}
}
```
### Response Fields
| Field | Description |
| ---------------------- | ----------------------------------------------------------- |
| `api` | API metadata (name, slug, description, verification status) |
| `endpoint.pathParams` | URL path parameters like `{id}` |
| `endpoint.queryParams` | Query string parameters |
| `endpoint.bodyParams` | Request body parameters |
| `endpoint.price` | Cost per call (or "dynamic" for variable pricing) |
| `usage` | Example URLs for calling this endpoint |
## Example
```bash cURL theme={null}
curl -X POST 'https://api.orthogonal.com/v1/details' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"api": "apollo",
"path": "/v1/people/match"
}'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/details', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
api: 'apollo',
path: '/v1/people/match'
})
});
const { api, endpoint } = await response.json();
console.log(`Price: ${endpoint.price}`);
console.log('Parameters:', endpoint.bodyParams);
```
```python Python theme={null}
import requests
import os
response = requests.post(
'https://api.orthogonal.com/v1/details',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'},
json={'api': 'apollo', 'path': '/v1/people/match'}
)
data = response.json()
print(f"Price: {data['endpoint']['price']}")
print('Parameters:', data['endpoint']['bodyParams'])
```
## Use Case: Building Dynamic Requests
Use details to construct valid API calls programmatically:
```javascript theme={null}
// 1. Get endpoint details
const details = await getDetails('apollo', '/v1/people/match');
// 2. Build request body from available params
const body = {};
for (const param of details.endpoint.bodyParams) {
if (userInput[param.name]) {
body[param.name] = userInput[param.name];
}
}
// 3. Make the API call
const result = await run('apollo', '/v1/people/match', { body });
```
# Integrate
Source: https://docs.orthogonal.com/api-reference/integrate
POST /v1/integrate
Get code snippets for an endpoint
Get ready-to-use code snippets for integrating an API endpoint into your application.
## Request
API slug (e.g., "olostep", "hunter")
Endpoint path (e.g., "/v1/scrapes")
Code format to return:
| Value | Description |
| ------------- | ------------------------- |
| `orth-sdk` | Orthogonal TypeScript SDK |
| `run-api` | Direct HTTP to /v1/run |
| `curl` | cURL command |
| `x402-fetch` | x402 payment (JavaScript) |
| `x402-python` | x402 payment (Python) |
| `all` | All available formats |
## Response
```json theme={null}
{
"success": true,
"api": {
"name": "Olostep",
"slug": "olostep"
},
"endpoint": {
"path": "/v1/scrapes",
"method": "POST",
"price": "$0.005"
},
"format": "all",
"snippets": {
"orth-sdk": "import Orthogonal from \"@orth/sdk\";\n\nconst orthogonal = new Orthogonal(...);\nconst result = await orthogonal.run({...});",
"run-api": "curl -X POST 'https://api.orthogonal.com/v1/run' ...",
"curl": "curl -X POST 'https://api.orthogonal.com/v1/run' ...",
"x402-fetch": "import { wrapFetchWithPayment } from \"x402-fetch\"; ...",
"x402-python": "from x402.clients.requests import x402_http_adapter ..."
},
"setup": {
"sdk": "npm install @orth/sdk && export ORTHOGONAL_API_KEY=orth_live_...",
"x402": "npm install x402-fetch viem && export PRIVATE_KEY=0x..."
}
}
```
## Example
```bash cURL theme={null}
curl -X POST 'https://api.orthogonal.com/v1/integrate' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"api": "hunter",
"path": "/domain-search",
"format": "all"
}'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/integrate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
api: 'hunter',
path: '/domain-search',
format: 'curl'
})
});
const { snippets } = await response.json();
console.log(snippets.curl);
```
```python Python theme={null}
import requests
import os
response = requests.post(
'https://api.orthogonal.com/v1/integrate',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'},
json={'api': 'hunter', 'path': '/domain-search', 'format': 'all'}
)
snippets = response.json()['snippets']
```
# API Reference
Source: https://docs.orthogonal.com/api-reference/introduction
Complete reference for the Orthogonal API
Base URL: `https://api.orthogonal.com`
## Authentication
All endpoints require an API key in the Authorization header:
```
Authorization: Bearer orth_live_xxxxxxxxxxxx
```
## Endpoints Overview
### Discovery API
Find and understand APIs programmatically.
| Method | Endpoint | Description |
| ------ | -------------------- | --------------------------------- |
| POST | `/v1/search` | Search APIs with natural language |
| POST | `/v1/details` | Get endpoint parameters |
| POST | `/v1/integrate` | Get code snippets |
| GET | `/v1/list-endpoints` | List all available APIs |
### Run API
Execute API calls.
| Method | Endpoint | Description |
| ------ | --------- | --------------------- |
| POST | `/v1/run` | Call any API endpoint |
## Response Format
All responses follow this structure:
```json theme={null}
{
"success": true,
"data": { ... },
"requestId": "run_xxxxx"
}
```
Error responses:
```json theme={null}
{
"success": false,
"error": "Error message",
"code": "ERROR_CODE"
}
```
## Error Codes
| Code | Description |
| ---------------------- | --------------------------- |
| `UNAUTHORIZED` | Invalid or missing API key |
| `INSUFFICIENT_CREDITS` | Account balance too low |
| `RATE_LIMITED` | Too many requests |
| `NOT_FOUND` | API or endpoint not found |
| `UPSTREAM_ERROR` | Error from the API provider |
# List Endpoints
Source: https://docs.orthogonal.com/api-reference/list-endpoints
GET /v1/list-endpoints
Get all available APIs and endpoints
List all discoverable APIs and their endpoints. Useful for browsing the catalog or building custom search interfaces.
## Request
Maximum number of APIs to return. Max: 500
Number of APIs to skip (for pagination)
## Response
```json theme={null}
{
"success": true,
"apis": [
{
"name": "Olostep",
"slug": "olostep",
"description": "Web scraping and content extraction API",
"baseUrl": "https://api.olostep.com",
"verified": true,
"endpoints": [
{
"path": "/v1/scrapes",
"method": "POST",
"description": "Scrape any webpage and get clean markdown",
"price": "$0.005",
"isPayable": true,
"docsUrl": "https://docs.olostep.com/api/scrape",
"queryParams": [],
"bodyParams": [
{
"name": "url",
"type": "string",
"required": true,
"description": "URL to scrape"
}
]
}
]
},
{
"name": "Hunter.io",
"slug": "hunter",
"description": "Email finder and verification",
"baseUrl": "https://api.hunter.io/v2",
"verified": true,
"endpoints": [
{
"path": "/domain-search",
"method": "POST",
"description": "Find email addresses for a domain",
"price": "$0.01",
"isPayable": true
}
]
}
],
"count": 2,
"totalEndpoints": 2,
"pagination": {
"limit": 100,
"offset": 0,
"hasMore": false
}
}
```
### Response Fields
| Field | Description |
| -------------------- | ----------------------------------------- |
| `apis` | Array of APIs with their endpoints |
| `apis[].slug` | API identifier for use with `/v1/run` |
| `apis[].verified` | Whether Orthogonal has verified this API |
| `apis[].endpoints` | All available endpoints for this API |
| `count` | Number of APIs returned |
| `totalEndpoints` | Total number of endpoints across all APIs |
| `pagination.hasMore` | Whether more results are available |
## Example
```bash cURL theme={null}
# List all APIs
curl 'https://api.orthogonal.com/v1/list-endpoints' \
-H 'Authorization: Bearer YOUR_API_KEY'
# Paginate through results
curl 'https://api.orthogonal.com/v1/list-endpoints?limit=50&offset=50' \
-H 'Authorization: Bearer YOUR_API_KEY'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/list-endpoints', {
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`
}
});
const { apis, totalEndpoints } = await response.json();
console.log(`Found ${apis.length} APIs with ${totalEndpoints} total endpoints`);
// List all scraping endpoints
const scrapingEndpoints = apis.flatMap(api =>
api.endpoints.filter(ep =>
ep.description?.toLowerCase().includes('scrape')
).map(ep => ({ api: api.slug, ...ep }))
);
```
```python Python theme={null}
import requests
import os
response = requests.get(
'https://api.orthogonal.com/v1/list-endpoints',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'}
)
data = response.json()
print(f"Found {data['count']} APIs with {data['totalEndpoints']} total endpoints")
# List all verified APIs
verified = [api for api in data['apis'] if api['verified']]
print(f"Verified APIs: {[api['name'] for api in verified]}")
```
## Pagination
For large result sets, use `limit` and `offset` to paginate:
```javascript theme={null}
async function getAllApis() {
const allApis = [];
let offset = 0;
const limit = 100;
while (true) {
const response = await fetch(
`https://api.orthogonal.com/v1/list-endpoints?limit=${limit}&offset=${offset}`,
{ headers: { 'Authorization': `Bearer ${apiKey}` } }
);
const { apis, pagination } = await response.json();
allApis.push(...apis);
if (!pagination.hasMore) break;
offset += limit;
}
return allApis;
}
```
## Search vs List
| Use Case | Endpoint |
| ----------------------------- | --------------------------------------- |
| Find APIs for a specific task | `POST /v1/search` with natural language |
| Browse all available APIs | `GET /v1/list-endpoints` |
| Get details for one endpoint | `POST /v1/details` |
# Run
Source: https://docs.orthogonal.com/api-reference/run
POST /v1/run
Execute an API call
Execute any API endpoint through Orthogonal. This is the main endpoint for making API calls.
## Request
API slug (e.g., "sixtyfour", "fiber"). Get this from search results.
Endpoint path (e.g., "/enrich-lead", "/find-email"). Get this from search results.
Request body for POST/PUT/PATCH endpoints. Can be an object or array depending on the endpoint.
Query string parameters as key-value pairs.
The HTTP method (GET, POST, etc.) is determined automatically based on the endpoint configuration.
## Response
```json theme={null}
{
"success": true,
"priceCents": 10,
"data": {
// Response from the underlying API
},
"requestId": "run_1234567890_abc123"
}
```
### Response Fields
| Field | Type | Description |
| ------------ | ------- | ------------------------------ |
| `success` | boolean | Whether the call succeeded |
| `priceCents` | number | Cost in cents (100 = \$1) |
| `data` | object | Response from the API provider |
| `requestId` | string | Unique request identifier |
## Examples
### Lead Enrichment (Apollo)
```bash cURL theme={null}
curl -X POST 'https://api.orthogonal.com/v1/run' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"api": "apollo",
"path": "/v1/people/match",
"body": {
"email": "ceo@stripe.com"
}
}'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/run', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
api: 'apollo',
path: '/v1/people/match',
body: {
email: 'ceo@stripe.com'
}
})
});
const { success, priceCents, data } = await response.json();
console.log(`Enriched for $${(priceCents / 100).toFixed(2)}`);
console.log(data);
```
```python Python theme={null}
import requests
import os
response = requests.post(
'https://api.orthogonal.com/v1/run',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'},
json={
'api': 'apollo',
'path': '/v1/people/match',
'body': {
'email': 'ceo@stripe.com'
}
}
)
result = response.json()
print(f"Enriched for ${result['priceCents'] / 100:.2f}")
print(result['data'])
```
### AI Web Search (LinkUp)
```bash theme={null}
curl -X POST 'https://api.orthogonal.com/v1/run' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"api": "linkup",
"path": "/v1/search",
"body": {
"q": "latest Series A funding rounds fintech 2026",
"depth": "standard"
}
}'
```
### Web Scraping (Olostep)
```bash theme={null}
curl -X POST 'https://api.orthogonal.com/v1/run' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"api": "olostep",
"path": "/v1/scrapes",
"body": {
"url_to_scrape": "https://stripe.com/about"
}
}'
```
### Multi-API Workflow
Chain APIs for complete lead research:
```bash theme={null}
# Step 1: Research company with AI search (LinkUp)
curl -X POST 'https://api.orthogonal.com/v1/run' \
-d '{"api": "linkup", "path": "/v1/search", "body": {"q": "Stripe company funding valuation 2026"}}'
# Step 2: Enrich the CEO (Apollo)
curl -X POST 'https://api.orthogonal.com/v1/run' \
-d '{"api": "apollo", "path": "/v1/people/match", "body": {"email": "ceo@stripe.com"}}'
# Step 3: Find more contacts at the company (Hunter)
curl -X POST 'https://api.orthogonal.com/v1/run' \
-d '{"api": "hunter", "path": "/domain-search", "body": {"domain": "stripe.com"}}'
```
## Error Handling
### Insufficient Credits (402)
```json theme={null}
{
"success": false,
"priceCents": 10,
"error": "Insufficient credits. Cost: $0.10, Available: $0.02"
}
```
### API Not Found (404)
```json theme={null}
{
"success": false,
"error": "API not found: invalid-slug"
}
```
## Error Codes
| Code | Description | Solution |
| ---- | -------------------- | -------------------------------- |
| 400 | Invalid request | Check api, path, and body format |
| 401 | Unauthorized | Check your API key |
| 402 | Insufficient credits | Add credits at dashboard |
| 404 | Not found | Check the api/path values |
| 5xx | Upstream error | Check the error message |
# Search
Source: https://docs.orthogonal.com/api-reference/search
POST /v1/search
Find APIs using natural language
Search for APIs by describing what you need. Uses semantic search to find the most relevant endpoints.
## Request
Natural language description of what you're looking for.
Examples:
* "enrich lead with contact info"
* "find email for a person"
* "company enrichment from domain"
Maximum number of results to return. Max: 50
## Response
Results are grouped by API, with each API containing its matching endpoints:
```json theme={null}
{
"success": true,
"results": [
{
"id": "api-uuid",
"name": "Apollo.io",
"slug": "apollo",
"baseUrl": "https://api.apollo.io",
"payableBaseUrl": "https://api.orthogonal.com/pay/apollo",
"endpoints": [
{
"id": "endpoint-uuid",
"path": "/v1/people/match",
"method": "POST",
"description": "Enrich a person by email, name, or LinkedIn URL",
"price": "0.03",
"isPayable": true,
"verified": true,
"score": 0.95
},
{
"path": "/v1/organizations/enrich",
"method": "POST",
"description": "Enrich a company by domain",
"price": "0.03",
"verified": true,
"score": 0.90
}
]
},
{
"id": "api-uuid-2",
"name": "Hunter.io",
"slug": "hunter",
"endpoints": [
{
"path": "/domain-search",
"method": "POST",
"description": "Find email addresses for a company domain",
"price": "0.01",
"verified": true,
"score": 0.85
}
]
}
],
"count": 3,
"apisCount": 2,
"prompt": "enrich lead with contact info",
"searchType": "semantic",
"responseTime": 145
}
```
### Response Fields
| Field | Description |
| -------------------------------- | ------------------------------------------------- |
| `results` | Array of APIs, each containing matching endpoints |
| `results[].slug` | API identifier to use with `/v1/run` |
| `results[].endpoints[].path` | Endpoint path to use with `/v1/run` |
| `results[].endpoints[].verified` | Whether the API is verified by Orthogonal |
| `results[].endpoints[].score` | Relevance score (0-1, higher is better) |
| `count` | Total number of endpoints returned |
## Example
```bash cURL theme={null}
curl -X POST 'https://api.orthogonal.com/v1/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"prompt": "enrich lead find email",
"limit": 5
}'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/search', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: 'enrich lead find email',
limit: 5
})
});
const { results } = await response.json();
// Get verified endpoints only
const verified = results.flatMap(api =>
api.endpoints.filter(ep => ep.verified)
);
console.log('Verified endpoints:', verified);
```
```python Python theme={null}
import requests
import os
response = requests.post(
'https://api.orthogonal.com/v1/search',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'},
json={'prompt': 'enrich lead find email', 'limit': 5}
)
results = response.json()['results']
# Get verified endpoints only
verified = [ep for api in results for ep in api['endpoints'] if ep.get('verified')]
print(f"Found {len(verified)} verified endpoints")
```
## Using Search Results
The `slug` and `path` from search results can be used directly with the [Run API](/api-reference/run):
```bash theme={null}
# From search: slug="apollo", path="/v1/people/match"
curl -X POST 'https://api.orthogonal.com/v1/run' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"api": "apollo",
"path": "/v1/people/match",
"body": {"email": "ceo@stripe.com"}
}'
```
# Transactions
Source: https://docs.orthogonal.com/api-reference/transactions
GET /v1/credits/transactions
View your credit transaction history
Returns your credit transaction history, including purchases, API call charges, and refunds.
## Authentication
Requires a valid API key via `Authorization: Bearer YOUR_API_KEY`.
## Query Parameters
Maximum number of transactions to return.
Offset for pagination.
## Response
```json theme={null}
{
"transactions": [
{
"id": "tx_abc123",
"type": "api_call",
"amountCents": -3000,
"description": "API call: apollo /v1/people/match",
"timestamp": "2026-02-27T10:30:00Z",
"metadata": {
"api": "apollo",
"path": "/v1/people/match"
}
},
{
"id": "tx_def456",
"type": "purchase",
"amountCents": 1000000,
"description": "Credit purchase: 10,000 credits",
"timestamp": "2026-02-25T14:00:00Z"
}
],
"pagination": {
"limit": 50,
"offset": 0,
"count": 2
}
}
```
### Response Fields
| Field | Type | Description |
| ---------------------------- | -------- | --------------------------------------------------------- |
| `transactions` | `array` | List of transactions |
| `transactions[].id` | `string` | Transaction ID |
| `transactions[].type` | `string` | Transaction type (`api_call`, `purchase`, `refund`, etc.) |
| `transactions[].amountCents` | `number` | Amount (negative for charges, positive for credits) |
| `transactions[].description` | `string` | Human-readable description |
| `transactions[].timestamp` | `string` | ISO 8601 timestamp |
| `transactions[].metadata` | `object` | Additional context (API slug, path, etc.) |
## Example
```bash cURL theme={null}
curl 'https://api.orthogonal.com/v1/credits/transactions?limit=20' \
-H 'Authorization: Bearer YOUR_API_KEY'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/credits/transactions?limit=20', {
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`
}
});
const { transactions } = await response.json();
// Separate charges and purchases
const charges = transactions.filter(t => t.amountCents < 0);
const purchases = transactions.filter(t => t.amountCents > 0);
console.log(`${charges.length} charges, ${purchases.length} purchases`);
```
```python Python theme={null}
import requests
import os
response = requests.get(
'https://api.orthogonal.com/v1/credits/transactions',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'},
params={'limit': 20}
)
transactions = response.json()['transactions']
for tx in transactions:
amount = tx['amountCents'] / 100000
print(f"{tx['type']:12} ${amount:+.4f} {tx['description']}")
```
# Usage
Source: https://docs.orthogonal.com/api-reference/usage
GET /v1/credits/usage
View your API usage history
Returns your API usage history with per-call cost breakdowns and a spend summary.
## Authentication
Requires a valid API key via `Authorization: Bearer YOUR_API_KEY`.
## Query Parameters
Maximum number of usage events to return.
Offset for pagination.
Number of days to look back.
## Response
```json theme={null}
{
"usage": [
{
"api": "apollo",
"path": "/v1/people/match",
"method": "POST",
"timestamp": "2026-02-27T10:30:00Z",
"cost": "$0.03",
"status": "completed"
},
{
"api": "hunter",
"path": "/domain-search",
"method": "POST",
"timestamp": "2026-02-27T09:15:00Z",
"cost": "$0.01",
"status": "completed"
}
],
"totalSpent": "$0.04",
"pagination": {
"limit": 50,
"offset": 0,
"count": 2,
"total": 2
}
}
```
### Response Fields
| Field | Type | Description |
| ------------------- | -------- | ----------------------------------------- |
| `usage` | `array` | List of API call events |
| `usage[].api` | `string` | API slug |
| `usage[].path` | `string` | Endpoint path called |
| `usage[].method` | `string` | HTTP method |
| `usage[].timestamp` | `string` | ISO 8601 timestamp |
| `usage[].cost` | `string` | Cost in dollars |
| `usage[].status` | `string` | Call status (`completed`, `failed`, etc.) |
| `totalSpent` | `string` | Total spend in dollars |
| `pagination.total` | `number` | Total number of events in the time range |
## Example
```bash cURL theme={null}
# Last 7 days of usage
curl 'https://api.orthogonal.com/v1/credits/usage?days=7&limit=20' \
-H 'Authorization: Bearer YOUR_API_KEY'
```
```bash CLI theme={null}
# Default: last 30 days
orth usage
# Last 7 days, 10 results
orth usage --days 7 --limit 10
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/credits/usage?days=7', {
headers: {
'Authorization': `Bearer ${process.env.ORTHOGONAL_API_KEY}`
}
});
const { usage, totalSpent } = await response.json();
console.log(`Total spent: ${totalSpent}`);
console.log(`API calls: ${usage.length}`);
```
```python Python theme={null}
import requests
import os
response = requests.get(
'https://api.orthogonal.com/v1/credits/usage',
headers={'Authorization': f'Bearer {os.environ["ORTHOGONAL_API_KEY"]}'},
params={'days': 7, 'limit': 20}
)
data = response.json()
print(f"Spent {data['totalSpent']} across {data['pagination']['total']} calls")
```
# Authentication
Source: https://docs.orthogonal.com/authentication
How to authenticate with the Orthogonal API
## API Keys
All requests to Orthogonal require an API key in the `Authorization` header:
```bash theme={null}
Authorization: Bearer orth_live_xxxxxxxxxxxx
```
## Getting Your Key
1. Sign in at [orthogonal.com](https://orthogonal.com)
2. Go to [Dashboard → API Keys](https://orthogonal.com/dashboard/settings/api-keys)
3. Copy your API key
## Key Types
| Type | Prefix | Use Case |
| ---- | ------------ | ----------------------------------------- |
| Live | `orth_live_` | Production usage, charged to your account |
| Test | `orth_test_` | Testing, no charges (limited APIs) |
## Environment Variables
We recommend storing your key in an environment variable:
```bash theme={null}
export ORTHOGONAL_API_KEY=orth_live_xxxxxxxxxxxx
```
Then reference it in your code:
```javascript Node.js theme={null}
const apiKey = process.env.ORTHOGONAL_API_KEY;
```
```python Python theme={null}
import os
api_key = os.environ['ORTHOGONAL_API_KEY']
```
```bash cURL theme={null}
curl -H "Authorization: Bearer $ORTHOGONAL_API_KEY" ...
```
# CLI
Source: https://docs.orthogonal.com/cli
Access Orthogonal APIs from the command line
The Orthogonal CLI (`orth`) lets you search, explore, and run tools and APIs from your terminal.
## Installation
```bash theme={null}
npm install -g @orth/cli
```
After installation, the CLI is available as `orth`.
## Authentication
Set your API key as an environment variable:
```bash theme={null}
export ORTHOGONAL_API_KEY=orth_live_your_key_here
```
Or pass it with each command:
```bash theme={null}
orth --key orth_live_your_key_here
```
Get your API key from the [dashboard](https://orthogonal.com/dashboard/settings/api-keys).
## Commands
### Search APIs
Find APIs by keyword:
```bash theme={null}
orth search "web scraping"
```
Output:
```
olostep Olostep (4 endpoints)
scrapegraph ScrapeGraph AI (3 endpoints)
riveter Riveter (2 endpoints)
```
### List All APIs
```bash theme={null}
orth api
```
### View API Endpoints
See all endpoints for an API:
```bash theme={null}
orth api olostep
```
Output:
```
Olostep (olostep)
POST /v1/scrapes $0.01
Scrape any webpage and get clean markdown
POST /v1/answers $0.02
Get AI-powered answers from web content
GET /v1/scrapes/{id} free
Check scrape status
```
### View Endpoint Details
Get full parameter details for an endpoint:
```bash theme={null}
orth api olostep /v1/scrapes
```
Output:
```
olostep/v1/scrapes
Scrape any webpage and get clean markdown
Price: $0.01
Body Parameters:
url_to_scrape* (string) - URL to scrape
formats (array) - Output formats (markdown, html, text)
wait_for (string) - CSS selector to wait for
Example:
orth run olostep /v1/scrapes --body '{"url_to_scrape": ""}'
```
### Call an API
Execute an API endpoint:
```bash theme={null}
# With query parameters
orth run hunter /v2/domain-search -q domain=orthogonal.com
# With JSON body
orth run olostep /v1/scrapes --body '{
"url_to_scrape": "https://news.ycombinator.com"
}'
```
### View Account Info
Check your balance and usage:
```bash theme={null}
orth account
```
## Examples
### Find someone's email
```bash theme={null}
orth run hunter /v2/email-finder -q domain=stripe.com -q first_name=Patrick -q last_name=Collison
```
### Scrape a webpage
```bash theme={null}
orth run olostep /v1/scrapes --body '{
"url_to_scrape": "https://example.com",
"formats": ["markdown"]
}'
```
### Search the web
```bash theme={null}
orth run tavily /search --body '{
"query": "latest AI news",
"search_depth": "advanced"
}'
```
### Verify an email
```bash theme={null}
orth run tomba /v1/email-verifier -q email=hello@orthogonal.com
```
## Options
| Flag | Description |
| ------------- | --------------------------- |
| `--key ` | API key (overrides env var) |
| `--json` | Output raw JSON |
| `--help` | Show help |
| `--version` | Show version |
## Environment Variables
| Variable | Description |
| -------------------- | ----------------------- |
| `ORTHOGONAL_API_KEY` | Your Orthogonal API key |
## Source Code
The CLI is open source: [github.com/orthogonal-sh/cli](https://github.com/orthogonal-sh/cli)
# Pricing
Source: https://docs.orthogonal.com/concepts/pricing
How Orthogonal pricing works
## Pay per call
You pay only for what you use. No subscriptions or minimums.
Each tool has a fixed price, shown in the [catalog](https://orthogonal.com/discover) and returned by search:
```json theme={null}
{
"api": "apollo",
"path": "/v1/people/match",
"price": 0.03,
"description": "Enrich a person by email"
}
```
## Pricing Tiers
Prices vary by API and complexity:
| Tier | Price Range | Examples |
| -------- | -------------- | ------------------------------------------------------ |
| Basic | $0.001 - $0.01 | Olostep scraping ($0.005), Hunter email search ($0.01) |
| Standard | $0.01 - $0.10 | Apollo enrichment ($0.03), LinkUp AI search ($0.004) |
| Premium | $0.10 - $1.00 | Deep research, AI analysis, bulk operations |
## Billing
* **Credits**: Pre-pay for credits at [orthogonal.com/dashboard/balance](https://www.orthogonal.com/dashboard/balance)
Every API response includes the cost:
```json theme={null}
{
"success": true,
"priceCents": 0.5,
"data": { ... }
}
```
## Free Tier
New accounts get \$5 in free credits to try the platform. No credit card required.
## Pay with crypto
You can also pay per call with stablecoins instead of credits, over x402 (USDC on Base) or MPP (USDC.e on Tempo). See [Payments](/payments).
# Orthogonal
Source: https://docs.orthogonal.com/index
Connect your agent to a catalog of paid tools and APIs.
Orthogonal connects your agent to a catalog of paid tools. Search for a tool, run it, and pay per request. No per-provider accounts to manage.
## How it works
Describe what you need, or browse the [catalog](https://orthogonal.com/discover). Search returns matching tools with their price.
Run the tool. Orthogonal connects to the provider for you and returns the result.
Every response includes the price. You pay only for the calls you make.
## Connect
Three ways to connect. All reach the same catalog. See the [Quickstart](/quickstart) for the two-minute version.
Add to Claude Desktop, Cursor, or any MCP client:
```json theme={null}
{
"mcpServers": {
"orthogonal": {
"url": "https://mcp.orthogonal.com"
}
}
}
```
Per-client steps and the tool list
```bash theme={null}
npm install -g @orth/cli
export ORTHOGONAL_API_KEY=orth_live_your_key
orth search "web scraping"
```
All commands and flags
```bash theme={null}
curl -X POST 'https://api.orthogonal.com/v1/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{"prompt": "web scraping"}'
```
Every endpoint and parameter
# MCP Server
Source: https://docs.orthogonal.com/mcp/setup
Add Orthogonal to Claude, Cursor, or any MCP-compatible client
Connect Claude, Cursor, or any [MCP](https://modelcontextprotocol.io) client to Orthogonal. Your agent can search the catalog and run any tool or API through the MCP tools below.
## Install
Go to Settings → Connectors and click **Add custom connector**.
Enter the name `Orthogonal` and the URL `https://mcp.orthogonal.com`, then click **Add**.
Click **Connect** and authorize with your Orthogonal account. The tools appear once it connects.
Press `Cmd+,` (Mac) or `Ctrl+,` (Windows/Linux) → MCP.
Click "Add Server" and enter:
* **Name:** `orthogonal`
* **URL:** `https://mcp.orthogonal.com`
Toggle the server on and start a new chat.
For any MCP-compatible client, point it at the Orthogonal server:
```json theme={null}
{
"mcpServers": {
"orthogonal": {
"url": "https://mcp.orthogonal.com"
}
}
}
```
## Available Tools
The server exposes seven tools:
| Tool | Description |
| ------------------- | -------------------------------------------------------------------- |
| `search` | Find APIs by describing what you need |
| `get_details` | Get full parameter info for an endpoint |
| `quote` | Get the exact price of a call without running it or spending credits |
| `use` | Execute an API call |
| `integrate` | Get ready-to-use code snippets |
| `batch_use` | Execute up to 20 API calls in parallel |
| `batch_get_details` | Get parameter info for up to 20 endpoints in parallel |
When you ask your assistant to do something like "enrich this lead", it will `search` for enrichment APIs, `get_details` to understand the parameters, then `use` to make the call and return the result.
## Verify Installation
Ask your assistant:
> "Search Orthogonal for APIs that can enrich leads by email."
If it's configured correctly, it will use the `search` tool and return results.
## Troubleshooting
1. Fully restart the client application.
2. Check that the URL is exactly `https://mcp.orthogonal.com`.
3. Verify your MCP client supports HTTP transport.
1. Check that your account has credits at [orthogonal.com/dashboard](https://orthogonal.com/dashboard).
2. Try a simple search first to verify connectivity.
3. Check the client's MCP logs for errors.
# Payments
Source: https://docs.orthogonal.com/payments
Pay per call with stablecoins over x402 or MPP.
By default you pay with prepaid [credits](/concepts/pricing). You can also pay per call with stablecoins over two rails:
* **x402** pays in USDC on Base, at `x402.orthogonal.com`.
* **MPP** (Machine Payments Protocol) pays in USDC.e on [Tempo](https://tempo.xyz), at `mpp.orthogonal.com`.
Both work the same way: your request gets a `402 Payment Required`, your client signs a payment and retries, and the payment is settled before the call runs.
## x402
Endpoints live at `https://x402.orthogonal.com/{api}/{path}`.
### CLI
Pay from the terminal with [`purl`](https://github.com/stripe/purl), a curl-compatible client that speaks x402. You need:
* A wallet funded with USDC on Base. Run `purl balance` to print your address, then send USDC to it.
```bash theme={null}
# Install
brew install stripe/purl/purl
# Create a wallet, then fund it with USDC on Base
purl wallet add
purl balance # prints your address — send USDC on Base to it
# Pay for and call the endpoint (USDC on Base, handled automatically)
purl -X POST \
-H "Content-Type: application/json" \
-d '{"url_to_scrape": "https://example.com"}' \
'https://x402.orthogonal.com/olostep/v1/scrapes'
```
### Code
Set `PRIVATE_KEY` to an EVM wallet holding USDC. The client handles the 402 for you.
```javascript Node.js theme={null}
import { wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const fetchWithPayment = wrapFetchWithPayment(fetch, account);
const res = await fetchWithPayment("https://x402.orthogonal.com/olostep/v1/scrapes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url_to_scrape: "https://example.com" }),
});
console.log(await res.json());
```
```python Python theme={null}
import os, requests
from eth_account import Account
from x402.clients.requests import x402_http_adapter
account = Account.from_key(os.environ["PRIVATE_KEY"])
session = requests.Session()
session.mount("https://", x402_http_adapter(account))
res = session.post(
"https://x402.orthogonal.com/olostep/v1/scrapes",
json={"url_to_scrape": "https://example.com"},
)
print(res.json())
```
Install with `npm install x402-fetch viem` or `pip install x402 eth-account requests`.
## MPP
Endpoints live at `https://mpp.orthogonal.com/{api}/{path}`.
### CLI
Pay from the terminal with `mppx`:
```bash theme={null}
# Create and autofund a Tempo account (stored in your keychain)
npx mppx account create
# Pay for and call the endpoint
npx mppx -X POST -J '{"url_to_scrape": "https://example.com"}' \
'https://mpp.orthogonal.com/olostep/v1/scrapes'
```
### Code
```typescript theme={null}
import { privateKeyToAccount } from "viem/accounts";
import { Mppx, tempo } from "mppx/client";
Mppx.create({
methods: [tempo({ account: privateKeyToAccount(process.env.PRIVATE_KEY) })],
});
// fetch now settles 402 payments on Tempo
const res = await fetch("https://mpp.orthogonal.com/olostep/v1/scrapes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url_to_scrape: "https://example.com" }),
});
console.log(await res.json());
```
Install with `npm install mppx viem`.
## Which tools support this?
Every payable tool in the [catalog](https://orthogonal.com/discover) works with both rails. Use the `integrate` tool (MCP or `/v1/integrate`) to get a ready-to-paste snippet for any endpoint.
# Quickstart
Source: https://docs.orthogonal.com/quickstart
Connect your agent in two minutes
## Connect
Pick one way to connect. All reach the same catalog.
Add the Orthogonal connector to Claude, Cursor, or any MCP client, then authorize with your account:
```json theme={null}
{
"mcpServers": {
"orthogonal": {
"url": "https://mcp.orthogonal.com"
}
}
}
```
Once connected, ask your assistant:
> "Search Orthogonal for APIs that enrich a lead by email, then run one."
Per-client steps, tool reference, and troubleshooting
Install the CLI and set your key:
```bash theme={null}
npm install -g @orth/cli
export ORTHOGONAL_API_KEY=orth_live_your_key
```
Search for an API and call it:
```bash theme={null}
orth search "enrich lead find email"
orth run sixtyfour /enrich-lead --body '{
"lead_info": {
"first_name": "Patrick",
"last_name": "Collison",
"company_domain": "stripe.com"
}
}'
```
All commands, flags, and examples
**1. Search for an API**
```bash cURL theme={null}
curl -X POST 'https://api.orthogonal.com/v1/search' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"prompt": "enrich lead find email", "limit": 5}'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/search', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ prompt: 'enrich lead find email', limit: 5 })
});
const { results } = await response.json();
console.log(results);
```
```python Python theme={null}
import requests
response = requests.post(
'https://api.orthogonal.com/v1/search',
headers={'Authorization': 'Bearer YOUR_API_KEY'},
json={'prompt': 'enrich lead find email', 'limit': 5}
)
print(response.json()['results'])
```
You'll get back matching APIs with their endpoints and pricing.
**2. Call the API**
```bash cURL theme={null}
curl -X POST 'https://api.orthogonal.com/v1/run' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"api": "sixtyfour",
"path": "/enrich-lead",
"body": {
"lead_info": {
"first_name": "Patrick",
"last_name": "Collison",
"company_domain": "stripe.com"
}
}
}'
```
```javascript Node.js theme={null}
const response = await fetch('https://api.orthogonal.com/v1/run', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
api: 'sixtyfour',
path: '/enrich-lead',
body: { lead_info: { first_name: 'Patrick', last_name: 'Collison', company_domain: 'stripe.com' } }
})
});
const { data, price } = await response.json();
console.log(`Cost: $${price}`);
console.log(data);
```
```python Python theme={null}
import requests
response = requests.post(
'https://api.orthogonal.com/v1/run',
headers={'Authorization': 'Bearer YOUR_API_KEY'},
json={
'api': 'sixtyfour',
'path': '/enrich-lead',
'body': {'lead_info': {'first_name': 'Patrick', 'last_name': 'Collison', 'company_domain': 'stripe.com'}}
}
)
result = response.json()
print(f"Cost: ${result['price']}")
print(result['data'])
```
The response includes the result plus what it cost:
```json theme={null}
{
"success": true,
"price": "0.10",
"data": {
"lead": {
"name": "Patrick Collison",
"title": "CEO",
"company": "Stripe",
"email": "patrick@stripe.com",
"linkedin_url": "linkedin.com/in/patrickcollison"
}
}
}
```
Every endpoint, parameter, and response
## Next steps
Every available API and its price.
Chain multiple APIs into one workflow.
# Examples
Source: https://docs.orthogonal.com/use-cases
Chain multiple APIs into complete workflows
Each example chains two to four tools to complete one task. Every example includes the CLI, Node.js, and Python.
## 1. Lead Research & Enrichment
**Goal:** Research a target company and build a complete profile of key contacts.
**Tools used:** LinkUp (AI search) → Hunter (email finding) → Apollo (enrichment)
```bash CLI theme={null}
# 1. Research the company with AI search
orth run linkup /search --body '{"q": "stripe company funding valuation news 2026", "depth": "standard"}'
# 2. Find contacts at the company
orth run hunter /domain-search --body '{"domain": "stripe.com"}'
# 3. Enrich the top contact (use an email from step 2)
orth run apollo /v1/people/match --body '{"email": "founder@stripe.com"}'
```
```javascript Node.js theme={null}
const ORTH_KEY = process.env.ORTHOGONAL_API_KEY;
async function run(api, path, body) {
const res = await fetch('https://api.orthogonal.com/v1/run', {
method: 'POST',
headers: {
'Authorization': `Bearer ${ORTH_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ api, path, body })
});
return res.json();
}
async function researchLead(company) {
// Step 1: Research the company with AI search
const research = await run('linkup', '/search', {
q: `${company} company funding valuation news 2026`,
depth: 'standard'
});
// Step 2: Find contacts at the company
const contacts = await run('hunter', '/domain-search', {
domain: `${company}.com`
});
// Step 3: Enrich the top contact
const topContact = contacts.data?.data?.emails?.[0];
if (topContact?.value) {
const enriched = await run('apollo', '/v1/people/match', {
email: topContact.value
});
return { research: research.data, contact: enriched.data };
}
return { research: research.data, contacts: contacts.data };
}
const result = await researchLead('stripe');
```
```python Python theme={null}
import requests
import os
ORTH_KEY = os.environ['ORTHOGONAL_API_KEY']
def run(api, path, body):
return requests.post(
'https://api.orthogonal.com/v1/run',
headers={'Authorization': f'Bearer {ORTH_KEY}'},
json={'api': api, 'path': path, 'body': body}
).json()
def research_lead(company):
# Step 1: Research the company with AI search
research = run('linkup', '/search', {
'q': f'{company} company funding valuation news 2026',
'depth': 'standard'
})
# Step 2: Find contacts at the company
contacts = run('hunter', '/domain-search', {
'domain': f'{company}.com'
})
# Step 3: Enrich the top contact
emails = contacts.get('data', {}).get('data', {}).get('emails', [])
if emails:
enriched = run('apollo', '/v1/people/match', {
'email': emails[0]['value']
})
return {'research': research['data'], 'contact': enriched['data']}
return {'research': research['data'], 'contacts': contacts['data']}
result = research_lead('stripe')
```
***
## 2. Competitor Social Intelligence
**Goal:** Monitor a competitor's social media presence and extract brand assets.
**Tools used:** Shofo (social scraping) → Brand.dev (brand extraction) → Olostep (web scraping)
```bash CLI theme={null}
# 1. Recent LinkedIn posts
orth run shofo /linkedin/company-posts --body '{"company_url": "https://linkedin.com/company/notionhq"}'
# 2. Brand assets - logos, colors
orth run brand-dev /v1/brand/retrieve --body '{"domain": "notion.so"}'
# 3. Scrape the pricing page
orth run olostep /v1/scrapes --body '{"url_to_scrape": "https://notion.so/pricing", "formats": ["markdown"]}'
```
```javascript Node.js theme={null}
async function analyzeCompetitor(domain, linkedinSlug) {
// Step 1: Get their recent LinkedIn posts
const posts = await run('shofo', '/linkedin/company-posts', {
company_url: `https://linkedin.com/company/${linkedinSlug}`
});
// Step 2: Extract brand assets - logos, colors
const brand = await run('brand-dev', '/v1/brand/retrieve', {
domain: domain
});
// Step 3: Scrape their pricing page
const pricing = await run('olostep', '/v1/scrapes', {
url_to_scrape: `https://${domain}/pricing`,
formats: ['markdown']
});
return {
socialActivity: posts.data,
brandAssets: brand.data,
pricingInfo: pricing.data
};
}
const intel = await analyzeCompetitor('notion.so', 'notionhq');
```
```python Python theme={null}
def analyze_competitor(domain, linkedin_slug):
# Step 1: Get their recent LinkedIn posts
posts = run('shofo', '/linkedin/company-posts', {
'company_url': f'https://linkedin.com/company/{linkedin_slug}'
})
# Step 2: Extract brand assets - logos, colors
brand = run('brand-dev', '/v1/brand/retrieve', {
'domain': domain
})
# Step 3: Scrape their pricing page
pricing = run('olostep', '/v1/scrapes', {
'url_to_scrape': f'https://{domain}/pricing',
'formats': ['markdown']
})
return {
'social_activity': posts['data'],
'brand_assets': brand['data'],
'pricing_info': pricing['data']
}
intel = analyze_competitor('notion.so', 'notionhq')
```
***
## 3. Event-Based Prospecting
**Goal:** Find people who recently engaged with relevant content and enrich them for outreach.
**Tools used:** Fiber (people search) → Shofo (social activity) → Tomba (email finding)
```bash CLI theme={null}
# 1. Find people matching your ICP
orth run fiber /v1/natural-language-search/profiles --body '{"query": "VP of Sales at Series B SaaS companies in San Francisco", "limit": 10}'
# For each profile from step 1, plug in its linkedin_url:
# 2. Check recent LinkedIn activity
orth run shofo /linkedin/user-posts --body '{"profile_url": ""}'
# 3. Find their email
orth run tomba /v1/linkedin --body '{"url": ""}'
```
```javascript Node.js theme={null}
async function findEngagedProspects(criteria) {
// Step 1: Find people matching your ICP
const prospects = await run('fiber', '/v1/natural-language-search/profiles', {
query: criteria,
limit: 10
});
const enrichedProspects = [];
for (const person of prospects.data?.profiles || []) {
// Step 2: Check their recent LinkedIn activity
const activity = await run('shofo', '/linkedin/user-posts', {
profile_url: person.linkedin_url
});
// Step 3: Find their email
const email = await run('tomba', '/v1/linkedin', {
url: person.linkedin_url
});
enrichedProspects.push({
...person,
recentPosts: activity.data?.posts?.slice(0, 3),
email: email.data?.data?.email
});
}
return enrichedProspects;
}
const prospects = await findEngagedProspects(
'VP of Sales at Series B SaaS companies in San Francisco'
);
```
```python Python theme={null}
def find_engaged_prospects(criteria):
# Step 1: Find people matching your ICP
prospects = run('fiber', '/v1/natural-language-search/profiles', {
'query': criteria,
'limit': 10
})
enriched_prospects = []
for person in prospects.get('data', {}).get('profiles', []):
# Step 2: Check their recent LinkedIn activity
activity = run('shofo', '/linkedin/user-posts', {
'profile_url': person['linkedin_url']
})
# Step 3: Find their email
email = run('tomba', '/v1/linkedin', {
'url': person['linkedin_url']
})
enriched_prospects.append({
**person,
'recent_posts': activity.get('data', {}).get('posts', [])[:3],
'email': email.get('data', {}).get('data', {}).get('email')
})
return enriched_prospects
prospects = find_engaged_prospects(
'VP of Sales at Series B SaaS companies in San Francisco'
)
```
***
## 4. Account-Based Marketing Research
**Goal:** Deep-dive on a target account - company intel, key people, and their social presence.
**Tools used:** Brand.dev (company data) → Fiber (find employees) → Apollo (enrich contacts)
```bash CLI theme={null}
# 1. Company brand info and products
orth run brand-dev /v1/brand/retrieve --body '{"domain": "figma.com"}'
# 2. Find decision makers
orth run fiber /v1/natural-language-search/profiles --body '{"query": "executives and VPs at figma.com company", "limit": 5}'
# For each profile from step 2, plug in its linkedin_url:
# 3. Enrich with contact details
orth run apollo /v1/people/match --body '{"linkedin_url": ""}'
```
```javascript Node.js theme={null}
async function abmResearch(targetDomain) {
// Step 1: Get company brand info and products
const company = await run('brand-dev', '/v1/brand/retrieve', {
domain: targetDomain
});
// Step 2: Find decision makers
const people = await run('fiber', '/v1/natural-language-search/profiles', {
query: `executives and VPs at ${targetDomain} company`,
limit: 5
});
// Step 3: Enrich each person with contact details
const enrichedPeople = [];
for (const person of people.data?.profiles || []) {
const enriched = await run('apollo', '/v1/people/match', {
linkedin_url: person.linkedin_url
});
enrichedPeople.push({
...person,
contact: enriched.data?.person
});
}
return {
company: company.data,
decisionMakers: enrichedPeople
};
}
const account = await abmResearch('figma.com');
```
```python Python theme={null}
def abm_research(target_domain):
# Step 1: Get company brand info and products
company = run('brand-dev', '/v1/brand/retrieve', {
'domain': target_domain
})
# Step 2: Find decision makers
people = run('fiber', '/v1/natural-language-search/profiles', {
'query': f'executives and VPs at {target_domain} company',
'limit': 5
})
# Step 3: Enrich each person with contact details
enriched_people = []
for person in people.get('data', {}).get('profiles', []):
enriched = run('apollo', '/v1/people/match', {
'linkedin_url': person['linkedin_url']
})
enriched_people.append({
**person,
'contact': enriched.get('data', {}).get('person')
})
return {
'company': company['data'],
'decision_makers': enriched_people
}
account = abm_research('figma.com')
```
***
## 5. Content & Trigger Monitoring
**Goal:** Monitor social channels for buying signals and company news.
**Tools used:** Shofo (X/Twitter monitoring) → LinkUp (news search) → Riveter (structured extraction)
```bash CLI theme={null}
# 1. Recent tweets from the company
orth run shofo /x/user-posts --body '{"username": "stripe"}'
# 2. Recent news and announcements
orth run linkup /search --body '{"q": "stripe.com announcement funding launch 2026", "depth": "standard"}'
# 3. Extract structured triggers from the news text (paste content from step 2)
orth run riveter /v1/run --body '{"input": "", "output_schema": {"type": "object", "properties": {"funding_events": {"type": "array", "items": {"type": "string"}}, "product_launches": {"type": "array", "items": {"type": "string"}}, "hiring_signals": {"type": "array", "items": {"type": "string"}}, "expansion_news": {"type": "array", "items": {"type": "string"}}}}}'
```
```javascript Node.js theme={null}
async function monitorTriggers(companyHandle, domain) {
// Step 1: Get recent tweets mentioning the company
const tweets = await run('shofo', '/x/user-posts', {
username: companyHandle
});
// Step 2: Search for recent news/announcements
const news = await run('linkup', '/search', {
q: `${domain} announcement funding launch 2026`,
depth: 'standard'
});
// Step 3: Extract structured triggers from the news
const triggers = await run('riveter', '/v1/run', {
input: news.data?.results?.map(r => r.content).join('\n\n'),
output_schema: {
type: 'object',
properties: {
funding_events: { type: 'array', items: { type: 'string' } },
product_launches: { type: 'array', items: { type: 'string' } },
hiring_signals: { type: 'array', items: { type: 'string' } },
expansion_news: { type: 'array', items: { type: 'string' } }
}
}
});
return {
socialActivity: tweets.data,
news: news.data,
triggers: triggers.data
};
}
const signals = await monitorTriggers('stripe', 'stripe.com');
```
```python Python theme={null}
def monitor_triggers(company_handle, domain):
# Step 1: Get recent tweets mentioning the company
tweets = run('shofo', '/x/user-posts', {
'username': company_handle
})
# Step 2: Search for recent news/announcements
news = run('linkup', '/search', {
'q': f'{domain} announcement funding launch 2026',
'depth': 'standard'
})
# Step 3: Extract structured triggers from the news
content = '\n\n'.join([r.get('content', '') for r in news.get('data', {}).get('results', [])])
triggers = run('riveter', '/v1/run', {
'input': content,
'output_schema': {
'type': 'object',
'properties': {
'funding_events': {'type': 'array', 'items': {'type': 'string'}},
'product_launches': {'type': 'array', 'items': {'type': 'string'}},
'hiring_signals': {'type': 'array', 'items': {'type': 'string'}},
'expansion_news': {'type': 'array', 'items': {'type': 'string'}}
}
}
})
return {
'social_activity': tweets['data'],
'news': news['data'],
'triggers': triggers['data']
}
signals = monitor_triggers('stripe', 'stripe.com')
```