# 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') ```