# Who Am I Source: https://monid.ai/docs/api/auth/whoami Return the identity behind the current API key or OAuth access token. ```text theme={null} GET /v1/auth/whoami ``` Return the authenticated user and (when present) workspace behind the current API key or OAuth access token. Useful to verify credentials. ## Headers | Header | Required | Description | | --------------- | -------- | ---------------------------------------- | | `Authorization` | Yes | `Bearer ` or OAuth access token | ## Example Request ```bash curl theme={null} curl "https://api.monid.ai/v1/auth/whoami" \ -H "Authorization: Bearer monid_live_..." ``` ```typescript TypeScript theme={null} const res = await fetch("https://api.monid.ai/v1/auth/whoami", { headers: { Authorization: "Bearer monid_live_..." }, }); ``` ```python Python theme={null} import requests res = requests.get( "https://api.monid.ai/v1/auth/whoami", headers={"Authorization": "Bearer monid_live_..."}, ) ``` ## 200 OK | Field | Type | Description | | ----------------------- | ------------------- | -------------------------------------------------------- | | `user` | object | The authenticated user | | `user.userId` | string | User identifier | | `user.username` | string | Username (may be empty) | | `user.email` | string \| undefined | Primary email, when known | | `user.metadata` | object | Free-form user metadata | | `user.createdAt` | string | Record creation time (ISO 8601) | | `user.updatedAt` | string | Record last-update time (ISO 8601) | | `workspace` | object \| undefined | The caller's workspace — absent when the caller has none | | `workspace.workspaceId` | string | Workspace identifier | | `workspace.name` | string | Workspace display name (may be empty) | | `workspace.slug` | string | Workspace slug (may be empty) | | `workspace.metadata` | object | Free-form workspace metadata | | `workspace.createdAt` | string | Record creation time (ISO 8601) | | `workspace.updatedAt` | string | Record last-update time (ISO 8601) | ### Example Response ```json theme={null} { "user": { "userId": "user_abc123", "username": "jane", "email": "jane@acme.com", "metadata": {}, "createdAt": "2026-01-15T09:00:00.000Z", "updatedAt": "2026-03-01T12:00:00.000Z" }, "workspace": { "workspaceId": "org_abc123", "name": "Acme, Inc.", "slug": "acme-inc", "metadata": {}, "createdAt": "2026-01-15T09:00:00.000Z", "updatedAt": "2026-03-01T12:00:00.000Z" } } ``` # List Workspaces Source: https://monid.ai/docs/api/auth/workspaces List the workspaces your API key or OAuth token has access to. ```text theme={null} GET /v1/auth/workspaces ``` List the workspaces your API key or OAuth access token has access to. Use the returned workspace IDs to set the `x-workspace-id` header on subsequent requests. ## Headers | Header | Required | Description | | --------------- | -------- | ---------------------------------------- | | `Authorization` | Yes | `Bearer ` or OAuth access token | ## Example Request ```bash curl theme={null} curl "https://api.monid.ai/v1/auth/workspaces" \ -H "Authorization: Bearer monid_live_..." ``` ```typescript TypeScript theme={null} const res = await fetch("https://api.monid.ai/v1/auth/workspaces", { headers: { Authorization: "Bearer monid_live_..." }, }); ``` ```python Python theme={null} import requests res = requests.get( "https://api.monid.ai/v1/auth/workspaces", headers={"Authorization": "Bearer monid_live_..."}, ) ``` ## 200 OK | Field | Type | Description | | -------------------------- | -------------- | ----------------------------------------------------------- | | `workspaces` | array | Workspaces the caller belongs to | | `workspaces[].workspaceId` | string | Workspace identifier — pass as `x-workspace-id` when needed | | `workspaces[].slug` | string \| null | Workspace slug. `null` when the workspace has no slug | ### Example Response ```json theme={null} { "workspaces": [ { "workspaceId": "org_abc123", "slug": "acme-inc" }, { "workspaceId": "org_def456", "slug": null } ] } ``` ## Using a Workspace ID With a Monid API key, the workspace is bound to the key — no header needed. When authenticating with an OAuth/JWT access token that doesn't carry an organization context, include the `x-workspace-id` header so Monid knows which workspace to operate against: ```bash theme={null} curl -X POST https://api.monid.ai/v1/discover \ -H "Authorization: Bearer " \ -H "x-workspace-id: org_abc123" \ -H "Content-Type: application/json" \ -d '{"query":"twitter posts"}' ``` # Discover Source: https://monid.ai/docs/api/discover Search for data endpoints using natural language. Search for data endpoints using natural language. The API uses AI-powered routing to match your query to the best available endpoints. ## Request ```text theme={null} POST /v1/discover ``` ### Headers | Header | Required | Description | | --------------- | -------- | ------------------ | | `Authorization` | Yes | `Bearer ` | | `Content-Type` | Yes | `application/json` | ### Body | Field | Type | Required | Description | | ---------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | string | Yes | A short natural language search query (1-1000 characters) | | `limit` | number | No | Maximum results to return (default 5, max 40) | | `minScore` | number | No | Minimum relevance score. Results scoring below this are filtered out. Scores fall in `(0, 1)`, so useful values are in that range (default 0.2; the schema accepts up to 2, but values above 1 return no results) | ### Example Request ```bash curl theme={null} curl -X POST https://api.monid.ai/v1/discover \ -H "Authorization: Bearer monid_live_..." \ -H "Content-Type: application/json" \ -d '{ "query": "twitter posts about AI", "limit": 5 }' ``` ```typescript TypeScript theme={null} const response = await fetch("https://api.monid.ai/v1/discover", { method: "POST", headers: { "Authorization": "Bearer monid_live_...", "Content-Type": "application/json", }, body: JSON.stringify({ query: "twitter posts about AI", limit: 5, }), }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api.monid.ai/v1/discover", headers={ "Authorization": "Bearer monid_live_...", "Content-Type": "application/json", }, json={ "query": "twitter posts about AI", "limit": 5, }, ) data = response.json() ``` ## Response ### 200 OK | Field | Type | Description | | -------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `results` | array | Matching endpoints | | `results[].provider` | string | Provider slug | | `results[].providerName` | string \| undefined | Provider display name (may be absent) | | `results[].endpoint` | string | Endpoint path | | `results[].description` | string | Endpoint description | | `results[].score` | number | Final relevance score in `(0, 1)`, used for sorting | | `results[].tags` | string\[] | Endpoint tags | | `results[].scoreBreakdown` | object | Per-signal breakdown of the score (`querierScore` plus one entry per signal) | | `results[].price` | object | Pricing information | | `results[].price.type` | string | Pricing model, e.g. `"PER_CALL"`, `"PER_RESULT"` (other types such as `"BY_PERIOD"`, `"PER_UNIT_MATRIX"`, `"METERED"` may appear with additional fields) | | `results[].price.amount` | object | Price as `{ "value": number, "currency": "USD" }` | | `results[].hints` | object \| undefined | Ready-to-use next-step commands (may be absent) | | `query` | string | The original search query | | `count` | number | Number of results returned | ### Example Response ```json theme={null} { "results": [ { "provider": "apify", "providerName": "Apify", "endpoint": "/apidojo/tweet-scraper", "description": "Scrape tweets by search terms, hashtags, or user handles", "score": 0.87, "tags": ["twitter", "social-media"], "scoreBreakdown": { "querierScore": 0.82 }, "price": { "type": "PER_CALL", "amount": { "value": 0.003, "currency": "USD" } } } ], "query": "twitter posts about AI", "count": 1 } ``` ## Next Step Use [`POST /v1/inspect`](/docs/api/inspect) to get full details for a discovered endpoint. # Inspect Source: https://monid.ai/docs/api/inspect Get full details for a specific data endpoint. Get full details for a specific data endpoint, including its input schema, pricing, and documentation. ## Request ```text theme={null} POST /v1/inspect ``` ### Headers | Header | Required | Description | | --------------- | -------- | ------------------ | | `Authorization` | Yes | `Bearer ` | | `Content-Type` | Yes | `application/json` | ### Body | Field | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------------------ | | `provider` | string | Yes | Provider slug (e.g., `"apify"`) | | `endpoint` | string | Yes | Endpoint path (e.g., `"/apidojo/tweet-scraper"`) | ### Example Request ```bash curl theme={null} curl -X POST https://api.monid.ai/v1/inspect \ -H "Authorization: Bearer monid_live_..." \ -H "Content-Type: application/json" \ -d '{ "provider": "apify", "endpoint": "/apidojo/tweet-scraper" }' ``` ```typescript TypeScript theme={null} const response = await fetch("https://api.monid.ai/v1/inspect", { method: "POST", headers: { "Authorization": "Bearer monid_live_...", "Content-Type": "application/json", }, body: JSON.stringify({ provider: "apify", endpoint: "/apidojo/tweet-scraper", }), }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api.monid.ai/v1/inspect", headers={ "Authorization": "Bearer monid_live_...", "Content-Type": "application/json", }, json={ "provider": "apify", "endpoint": "/apidojo/tweet-scraper", }, ) data = response.json() ``` ## Response ### 200 OK | Field | Type | Description | | ------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Unique inspection identifier | | `provider` | string | Provider slug | | `providerName` | string \| undefined | Provider display name (may be absent) | | `endpoint` | string | Endpoint path | | `method` | string \| undefined | HTTP method for this endpoint | | `description` | string | What the endpoint does | | `summary` | string \| undefined | Detailed overview | | `input` | object \| undefined | Structured input — a JSON Schema per parameter location | | `input.pathParams` | object \| undefined | JSON Schema for URL path parameters | | `input.queryParams` | object \| undefined | JSON Schema for query string parameters | | `input.body` | object \| undefined | JSON Schema for the request body | | `input.bodyType` | string \| undefined | Body content type: `"json"`, `"form"`, or `"multipart"` | | `price` | object \| undefined | Pricing information | | `price.type` | string | Pricing model, e.g. `"PER_CALL"`, `"PER_RESULT"` (other types such as `"BY_PERIOD"`, `"PER_UNIT_MATRIX"`, `"METERED"` may appear with additional fields) | | `price.amount` | object | Price as `{ "value": number, "currency": "USD" }` | | `price.flatFee` | object \| undefined | Base fee per call as `{ "value": number, "currency": "USD" }` (PER\_RESULT only) | | `price.notes` | string\[] \| undefined | Pricing notes | | `docUrl` | string \| undefined | Link to provider documentation | | `notes` | string\[] \| undefined | Operator-curated notes — quirks, pitfalls, best practices | | `tags` | string\[] | Endpoint tags (e.g. `["verified"]`) | | `hints` | object \| undefined | Ready-to-use next-step commands, keyed by a descriptive phrase | ### Example Response ```json theme={null} { "id": "01HXYZ...", "provider": "apify", "providerName": "Apify", "endpoint": "/apidojo/tweet-scraper", "method": "POST", "description": "Scrape tweets by search terms, hashtags, or user handles", "summary": "A powerful Twitter scraping tool that allows you to extract tweets based on search queries.", "input": { "body": { "type": "object", "properties": { "searchTerms": { "type": "array", "items": { "type": "string" }, "description": "List of search terms to query" }, "maxItems": { "type": "number", "description": "Maximum number of items to return per search term" } } }, "bodyType": "json" }, "price": { "type": "PER_CALL", "amount": { "value": 0.003, "currency": "USD" } }, "docUrl": "https://apify.com/apidojo/tweet-scraper", "tags": ["verified"], "hints": { "run this endpoint": "curl -X POST https://api.monid.ai/v1/run -H 'Authorization: Bearer ' -H 'Content-Type: application/json' -d '{\"provider\":\"apify\",\"endpoint\":\"/apidojo/tweet-scraper\",\"input\":{...}}'" } } ``` ## Next Step Use [`POST /v1/run`](/docs/api/run) to execute the endpoint with your input. # API Overview Source: https://monid.ai/docs/api/overview Discover, inspect, and run data endpoints programmatically. The Monid HTTP API lets you discover, inspect, and run data endpoints programmatically. ## Base URL ```text theme={null} https://api.monid.ai ``` ## Authentication All `/v1/*` endpoints require Bearer authentication — a Monid API key or an OAuth/JWT access token: ```text theme={null} Authorization: Bearer monid_live_... ``` Create an API key at [https://app.monid.ai/access/api-keys](https://app.monid.ai/access/api-keys). ## Workspace Header When you authenticate with a Monid API key, the workspace is bound to the key — no `x-workspace-id` header is needed. The header only applies when authenticating with an OAuth/JWT access token that does not carry an organization context; in that case pass it explicitly. Get the list of workspaces the caller can access with [`GET /v1/auth/workspaces`](/docs/api/auth/workspaces). ```text theme={null} x-workspace-id: org_abc123 ``` ## Endpoints ### Auth | Method | Path | Description | | ------ | -------------------------------------------------- | -------------------------------------------------- | | `GET` | [`/v1/auth/whoami`](/docs/api/auth/whoami) | Return the identity behind the current credentials | | `GET` | [`/v1/auth/workspaces`](/docs/api/auth/workspaces) | List workspaces the caller can access | ### Endpoints | Method | Path | Description | | ------ | ------------------------------------ | ------------------------- | | `POST` | [`/v1/discover`](/docs/api/discover) | Search for data endpoints | | `POST` | [`/v1/inspect`](/docs/api/inspect) | Get full endpoint details | | `POST` | [`/v1/run`](/docs/api/run) | Execute a data endpoint | ### Runs | Method | Path | Description | | ------ | --------------------------------------------- | ---------------------------- | | `GET` | [`/v1/runs`](/docs/api/runs/list) | List runs | | `GET` | [`/v1/runs/:runId`](/docs/api/runs/get) | Get run status and results | | `POST` | [`/v1/runs/:runId/stop`](/docs/api/runs/stop) | Stop a queued or running run | ### Wallet | Method | Path | Description | | ------ | ------------------------------------------------------ | ------------------------ | | `GET` | [`/v1/wallet/balance`](/docs/api/wallet/balance) | Get current balance | | `GET` | [`/v1/wallet/activities`](/docs/api/wallet/activities) | List wallet transactions | ## Request Format All request bodies must be JSON with `Content-Type: application/json`. ```bash theme={null} curl -X POST https://api.monid.ai/v1/discover \ -H "Authorization: Bearer monid_live_..." \ -H "Content-Type: application/json" \ -d '{"query": "twitter posts"}' ``` ## Response Format All responses return JSON. Successful responses return the resource directly. Error responses return: ```json theme={null} { "code": 400, "message": "Descriptive error message" } ``` ## Pagination All list endpoints use cursor-based pagination: **Request:** | Parameter | Type | Default | Description | | --------- | ------ | ------- | ---------------------------------------------------------- | | `limit` | number | varies | Maximum items to return (default and max vary by endpoint) | | `cursor` | string | — | Opaque cursor from a previous response | **Response:** ```json theme={null} { "items": [], "cursor": "eyJsYXN0..." } ``` If `cursor` is `null` or absent, you've reached the last page. ## Error Codes | Code | Meaning | | ----- | ---------------------------------------------------------------------------------------------------------- | | `202` | Accepted — the operation runs asynchronously (async runs, stop requests) | | `400` | Bad request — invalid input, malformed JSON, or validation error | | `401` | Unauthorized — missing or invalid API key | | `402` | Payment required — insufficient wallet balance | | `403` | Forbidden — key is valid but not associated with a workspace, or the resource belongs to another workspace | | `404` | Not found — resource doesn't exist | | `408` | Request timeout — a synchronous run timed out (`TIMED_OUT`) | | `409` | Conflict — e.g. stopping a run that is terminal or not stoppable | | `500` | Internal server error | | `502` | Bad gateway — the upstream provider rejected the call (e.g. provider-side payment error) | | `503` | Service unavailable — e.g. the wallet is not active | ## Request Tracing Every request is assigned a unique request ID via the `x-request-id` header. Include this ID when reporting issues. # Run Source: https://monid.ai/docs/api/run Execute a data endpoint. Execute a data endpoint. For providers which are executed synchronously (e.g. People Data Labs), they return the results immediately; for others (e.g. Apify), the server will return 202 with a run ID and processes the request in the background. ## Request ```text theme={null} POST /v1/run ``` ### Headers | Header | Required | Description | | --------------- | -------- | ------------------ | | `Authorization` | Yes | `Bearer ` | | `Content-Type` | Yes | `application/json` | ### Body | Field | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------------------------------------------ | | `provider` | string | Yes | Provider slug (e.g., `"apify"`) | | `endpoint` | string | Yes | Endpoint path (e.g., `"/apidojo/tweet-scraper"`) | | `input` | object | No | Input parameters matching the endpoint's input schema (defaults to `{}`) | ### Example Request ```bash curl theme={null} curl -X POST https://api.monid.ai/v1/run \ -H "Authorization: Bearer monid_live_..." \ -H "Content-Type: application/json" \ -d '{ "provider": "apify", "endpoint": "/apidojo/tweet-scraper", "input": { "searchTerms": ["AI"], "maxItems": 10 } }' ``` ```typescript TypeScript theme={null} const response = await fetch("https://api.monid.ai/v1/run", { method: "POST", headers: { "Authorization": "Bearer monid_live_...", "Content-Type": "application/json", }, body: JSON.stringify({ provider: "apify", endpoint: "/apidojo/tweet-scraper", input: { searchTerms: ["AI"], maxItems: 10, }, }), }); const data = await response.json(); if (response.status === 202) { // Async provider — poll for results const runId = data.runId; let result; while (true) { const poll = await fetch(`https://api.monid.ai/v1/runs/${runId}`, { headers: { "Authorization": "Bearer monid_live_..." }, }); result = await poll.json(); if (["COMPLETED", "FAILED", "BLOCKED", "STOPPED", "TIMED_OUT"].includes(result.status)) break; await new Promise((resolve) => setTimeout(resolve, 5000)); } console.log(result.output); } else { // Sync provider (e.g. PDL) — run completed immediately. // The HTTP status mirrors the provider's status (200, 404, 429, ...). console.log(data.output); } ``` ```python Python theme={null} import requests import time response = requests.post( "https://api.monid.ai/v1/run", headers={ "Authorization": "Bearer monid_live_...", "Content-Type": "application/json", }, json={ "provider": "apify", "endpoint": "/apidojo/tweet-scraper", "input": { "searchTerms": ["AI"], "maxItems": 10, }, }, ) data = response.json() if response.status_code == 202: # Async provider — poll for results run_id = data["runId"] while True: result = requests.get( f"https://api.monid.ai/v1/runs/{run_id}", headers={"Authorization": "Bearer monid_live_..."}, ).json() if result["status"] in ("COMPLETED", "FAILED", "BLOCKED", "STOPPED", "TIMED_OUT"): break time.sleep(5) else: # Sync provider — run completed immediately. # The HTTP status mirrors the provider's status (200, 404, 429, ...). result = data if result["status"] == "FAILED": print("Infrastructure error") elif result["status"] in ("BLOCKED", "STOPPED", "TIMED_OUT"): print(f"Run {result['status'].lower()}: {result.get('reason', 'no output returned')}") elif result.get("providerResponse", {}).get("httpStatus", 200) >= 400: print(f"Provider error: HTTP {result['providerResponse']['httpStatus']}") else: print(f"Success: {result.get('output')}") ``` ## Response The response depends on the provider's execution mode: * **Sync providers** return the completed result immediately — no polling needed. The HTTP status **mirrors the provider's HTTP status**: `200` on success, `404`/`429`/`500` etc. when the provider returned that status (a provider-side `402` is surfaced as `502`). A synchronous run that times out returns `408` (`TIMED_OUT`). * **Async providers** return `202` with a run ID. Poll [`GET /v1/runs/:runId`](/docs/api/runs/get) for results. * A run rejected by a control gate returns `200` with `status: "BLOCKED"` plus `reason` and `controls` fields. ### Completed (Sync) The run completed immediately. Results are included in the response, and the HTTP status mirrors the provider's status. | Field | Type | Description | | ----------------------------- | ------------------- | ----------------------------------------------------------------------- | | `runId` | string | Unique run identifier (ULID) | | `provider` | string | Provider slug | | `endpoint` | string | Endpoint path | | `status` | string | Run status: `"COMPLETED"` | | `output` | any \| null | Provider output data | | `providerResponse` | object | Provider response metadata | | `providerResponse.httpStatus` | number | Provider HTTP status code | | `providerResponse.error` | object \| undefined | Provider error body (non-2xx) | | `price` | object | Endpoint pricing (`amount` is `{ "value": number, "currency": "USD" }`) | | `billing` | object \| undefined | Billing breakdown (absent until settled) | | `billedUnits` | number | Units of the price's billing unit consumed (`0` when nothing billable) | | `resultCount` | number | Deprecated alias of `billedUnits` | | `resources` | array \| undefined | Resources provisioned by this run, if any | | `hints` | object \| undefined | Ready-to-use next-step commands | | `createdAt` | string | ISO 8601 timestamp | | `completedAt` | string | ISO 8601 timestamp | #### Example: Sync Success ```json theme={null} { "runId": "01HXYZ1234567890ABCDEF", "provider": "pdl", "endpoint": "/person/enrich", "status": "COMPLETED", "output": { "full_name": "John Doe", "linkedin_url": "linkedin.com/in/johndoe" }, "providerResponse": { "httpStatus": 200 }, "price": { "type": "PER_CALL", "amount": { "value": 0.003, "currency": "USD" } }, "billing": { "calculatedCost": { "value": 3000, "unit": "MICRO_DOLLAR", "currency": "USD" }, "actualCost": { "value": 0, "unit": "MICRO_DOLLAR", "currency": "USD" }, "reportedCost": { "value": 3000, "unit": "MICRO_DOLLAR", "currency": "USD" } }, "billedUnits": 1, "resultCount": 1, "createdAt": "2026-03-28T10:30:00.000Z", "completedAt": "2026-03-28T10:30:01.000Z" } ``` #### Example: Sync Provider Error The run completed, but the provider returned an error. Note `status` is still `"COMPLETED"` — the run lifecycle finished. The response's HTTP status mirrors the provider's status (here: `404 Not Found`). ```json theme={null} { "runId": "01HXYZ1234567890ABCDEF", "provider": "pdl", "endpoint": "/person/enrich", "status": "COMPLETED", "output": null, "providerResponse": { "httpStatus": 404, "error": { "status": 404, "message": "No match found for the given query" } }, "price": { "type": "PER_CALL", "amount": { "value": 0.003, "currency": "USD" } }, "billing": { "calculatedCost": { "value": 3000, "unit": "MICRO_DOLLAR", "currency": "USD" }, "actualCost": { "value": 0, "unit": "MICRO_DOLLAR", "currency": "USD" }, "reportedCost": { "value": 0, "unit": "MICRO_DOLLAR", "currency": "USD" } }, "billedUnits": 0, "resultCount": 0, "createdAt": "2026-03-28T10:30:00.000Z", "completedAt": "2026-03-28T10:30:01.000Z" } ``` ### 202 Accepted (Async) The run has been created. Poll [`GET /v1/runs/:runId`](/docs/api/runs/get) for results. | Field | Type | Description | | ----------- | ------ | -------------------------------------------------- | | `runId` | string | Unique run identifier (ULID) | | `provider` | string | Provider slug | | `endpoint` | string | Endpoint path | | `status` | string | `"READY"` — the run is queued and about to execute | | `price` | object | Endpoint pricing | | `createdAt` | string | ISO 8601 timestamp | #### Example ```json theme={null} { "runId": "01HXYZ1234567890ABCDEF", "provider": "apify", "endpoint": "/apidojo/tweet-scraper", "status": "READY", "price": { "type": "PER_CALL", "amount": { "value": 0.003, "currency": "USD" } }, "createdAt": "2026-03-28T10:30:00.000Z" } ``` ## Status vs Provider HTTP Status Every completed run has two independent indicators: 1. **`status`** — the run lifecycle. `"COMPLETED"` means the provider was called and responded. `"FAILED"` means an infrastructure error (our fault). `"BLOCKED"` means a control gate rejected the run before execution. `"STOPPED"` means the run was stopped by request. `"TIMED_OUT"` means the run exceeded its time budget. 2. **`providerResponse.httpStatus`** — the provider's HTTP response code. `200` = data returned. `404` = no match. `429` = rate limited. `500` = provider error. A run with `status: "COMPLETED"` and `providerResponse.httpStatus: 404` is normal — the run completed, the provider just found no data. Provider errors are not charged. See [Status vs Provider HTTP Status](/docs/api/runs/get#status-vs-provider-http-status) for the full reference. ## Polling for Results For async runs (`202` response), poll [`GET /v1/runs/:runId`](/docs/api/runs/get) to check status and retrieve results. Most runs complete within 1–120 seconds. When polling, check two things: 1. **`status`** — wait until a terminal status: `"COMPLETED"`, `"FAILED"`, `"BLOCKED"`, `"STOPPED"`, or `"TIMED_OUT"` 2. **`providerResponse.httpStatus`** — once completed, check if the provider returned a success (2xx) or error (4xx/5xx) ## Next Step Use [`GET /v1/runs/:runId`](/docs/api/runs/get) to retrieve run results. # Get Run Source: https://monid.ai/docs/api/runs/get Get the status and results of a specific run. ```text theme={null} GET /v1/runs/:runId ``` Get the status and results of a specific run. ## Headers | Header | Required | Description | | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Authorization` | Yes | `Bearer ` | | `x-workspace-id` | No | Only needed with OAuth/JWT tokens without an org context — with a Monid API key the workspace is bound to the key. See [`GET /v1/auth/workspaces`](/docs/api/auth/workspaces) | ## Path Parameters | Parameter | Type | Description | | --------- | ------ | --------------------- | | `runId` | string | The run ID to look up | ## Example Request ```bash curl theme={null} curl "https://api.monid.ai/v1/runs/01HXYZ1234567890ABCDEF" \ -H "Authorization: Bearer monid_live_..." ``` ```typescript TypeScript theme={null} const res = await fetch( "https://api.monid.ai/v1/runs/01HXYZ1234567890ABCDEF", { headers: { Authorization: "Bearer monid_live_...", }, }, ); ``` ## 200 OK | Field | Type | Description | | ------------------ | -------------------- | ----------------------------------------------------------------------- | | `runId` | string | Run identifier | | `caller` | string | Prefixed caller id (e.g. `USER#`) | | `provider` | string | Provider slug | | `providerName` | string \| undefined | Provider display name | | `endpoint` | string | Endpoint path | | `status` | string | Run status | | `stoppable` | boolean \| undefined | Whether the run may be stopped (present only for non-terminal runs) | | `reason` | string \| undefined | `BLOCKED` only — why the control gate rejected the run | | `controls` | array \| undefined | `BLOCKED` only — the blocking control(s) | | `input` | object | Input parameters | | `output` | any \| null | Provider output data (terminal runs only) | | `providerResponse` | object \| undefined | Provider response metadata (incl. `httpStatus`) | | `price` | object | Endpoint pricing (`amount` is `{ "value": number, "currency": "USD" }`) | | `cost` | object \| undefined | Actual cost charged | | `billedUnits` | number \| undefined | Units of the price's billing unit consumed | | `resultCount` | number \| undefined | Deprecated alias of `billedUnits` | | `resources` | array \| undefined | Provider resources created by this run | | `hints` | object \| undefined | Ready-to-use next-step commands | | `createdAt` | string | ISO 8601 timestamp | | `startedAt` | string \| undefined | When execution started | | `completedAt` | string \| undefined | When execution finished | ### 403 Forbidden Returned when the run belongs to a different workspace than the caller's. ## Status vs Provider HTTP Status Every run has two independent indicators: 1. **`status`** — the run lifecycle status. Did the run itself complete? 2. **`providerResponse.httpStatus`** — the provider's HTTP response code. Did the data provider return good data? ### Run Status | Status | Meaning | | ----------- | ------------------------------------------------------------------------- | | `READY` | Queued, waiting to start | | `RUNNING` | Actively executing | | `STOPPING` | Stop requested, shutting down (transient) | | `COMPLETED` | Run finished — the provider was called and responded | | `FAILED` | Infrastructure failure — pipeline crash or internal error (our fault) | | `BLOCKED` | Rejected by a control gate before execution (see `reason` and `controls`) | | `STOPPED` | Stopped by request before completing (zero-billed) | | `TIMED_OUT` | Ran past its time budget (terminal; distinct from `FAILED`) | ### Provider HTTP Status When a run is `COMPLETED`, check `providerResponse.httpStatus`: | HTTP Status | Meaning | | ----------- | ------------------------------------------------- | | `200` | Success — `output` contains results | | `400` | Bad request — invalid parameters sent to provider | | `404` | Not found — no match for the query | | `429` | Rate limited — provider throttled the request | | `500` | Provider error — the provider's service failed | Provider errors are **not charged** — `cost.value` will be `0`. ## Caching Terminal runs include `Cache-Control: private, max-age=60` (60 seconds). Running runs are not cached. # List Runs Source: https://monid.ai/docs/api/runs/list List runs for your workspace. ```text theme={null} GET /v1/runs ``` List runs for your workspace with cursor-based pagination. ## Headers | Header | Required | Description | | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Authorization` | Yes | `Bearer ` | | `x-workspace-id` | No | Only needed with OAuth/JWT tokens without an org context — with a Monid API key the workspace is bound to the key. See [`GET /v1/auth/workspaces`](/docs/api/auth/workspaces) | ## Query Parameters | Parameter | Type | Default | Description | | --------- | ------ | ------- | -------------------------------------------------- | | `limit` | number | 10 | Maximum runs to return (1–100) | | `status` | string | — | Filter by run status (e.g. `RUNNING`, `COMPLETED`) | | `cursor` | string | — | Pagination cursor from a previous response | ## Example Request ```bash curl theme={null} curl "https://api.monid.ai/v1/runs?limit=10" \ -H "Authorization: Bearer monid_live_..." ``` ```typescript TypeScript theme={null} const res = await fetch("https://api.monid.ai/v1/runs?limit=10", { headers: { Authorization: "Bearer monid_live_...", }, }); ``` ```python Python theme={null} import requests res = requests.get( "https://api.monid.ai/v1/runs", headers={ "Authorization": "Bearer monid_live_...", }, params={"limit": 10}, ) ``` ## 200 OK | Field | Type | Description | | -------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------- | | `items` | array | List of run summaries | | `items[].runId` | string | Run identifier | | `items[].caller` | string | Prefixed caller id (e.g. `USER#`) | | `items[].provider` | string | Provider slug | | `items[].providerName` | string \| undefined | Provider display name | | `items[].endpoint` | string | Endpoint path | | `items[].status` | string | Run status: `READY`, `RUNNING`, `STOPPING`, `COMPLETED`, `FAILED`, `BLOCKED`, `STOPPED`, or `TIMED_OUT` | | `items[].stoppable` | boolean \| undefined | Whether the run may be stopped (non-terminal runs only) | | `items[].providerResponse` | object \| undefined | Provider response metadata (incl. `httpStatus`) | | `items[].price` | object | Endpoint pricing (`amount` is `{ "value": number, "currency": "USD" }`) | | `items[].cost` | object \| undefined | Actual cost charged | | `items[].billedUnits` | number \| undefined | Units of the price's billing unit consumed | | `items[].resultCount` | number \| undefined | Deprecated alias of `billedUnits` | | `items[].createdAt` | string | ISO 8601 timestamp | | `items[].startedAt` | string \| undefined | When execution started | | `items[].completedAt` | string \| undefined | When execution finished | | `cursor` | string \| null | Next-page cursor. `null` if last page | ### Example Response ```json theme={null} { "items": [ { "runId": "01HXYZ1234567890ABCDEF", "caller": "USER#user_abc123", "provider": "apify", "providerName": "Apify", "endpoint": "/apidojo/tweet-scraper", "status": "COMPLETED", "providerResponse": { "httpStatus": 200 }, "price": { "type": "PER_CALL", "amount": { "value": 0.003, "currency": "USD" } }, "cost": { "value": 0.003, "currency": "USD" }, "billedUnits": 1, "createdAt": "2026-03-28T10:30:00.000Z", "startedAt": "2026-03-28T10:30:00.000Z", "completedAt": "2026-03-28T10:30:01.000Z" } ], "cursor": null } ``` # Stop Run Source: https://monid.ai/docs/api/runs/stop Stop a running run. ```text theme={null} POST /v1/runs/:runId/stop ``` Stop a run that is `READY` or `RUNNING`. Stopping is asynchronous: the request is acknowledged with `202` and status `STOPPING`; poll [`GET /v1/runs/:runId`](/docs/api/runs/get) for the terminal state. ## Headers | Header | Required | Description | | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Authorization` | Yes | `Bearer ` | | `x-workspace-id` | No | Only needed with OAuth/JWT tokens without an org context — with a Monid API key the workspace is bound to the key. See [`GET /v1/auth/workspaces`](/docs/api/auth/workspaces) | ## Path Parameters | Parameter | Type | Description | | --------- | ------ | ------------------ | | `runId` | string | The run ID to stop | ## Example Request ```bash curl theme={null} curl -X POST "https://api.monid.ai/v1/runs/01HXYZ1234567890ABCDEF/stop" \ -H "Authorization: Bearer monid_live_..." ``` ```typescript TypeScript theme={null} const res = await fetch( "https://api.monid.ai/v1/runs/01HXYZ1234567890ABCDEF/stop", { method: "POST", headers: { Authorization: "Bearer monid_live_...", }, }, ); ``` ## 202 Accepted The stop request was accepted. The run transitions to `STOPPING` and settles asynchronously — poll [`GET /v1/runs/:runId`](/docs/api/runs/get) for the terminal state. ```json theme={null} { "runId": "01HXYZ1234567890ABCDEF", "status": "STOPPING", "message": "Stop requested" } ``` ## 409 Conflict Returned when the run cannot be stopped: * The run is already terminal (`COMPLETED`, `FAILED`, `BLOCKED`, `STOPPED`, `TIMED_OUT`) * The endpoint does not support stopping (`stoppable: false` on the run) A `403` is returned if the run belongs to a different workspace. The settlement depends on the endpoint's pricing model: runs on **metered** endpoints bill for the usage accrued before the stop and settle as `COMPLETED`; all other stopped runs settle as `STOPPED` and are zero-billed. # List Activities Source: https://monid.ai/docs/api/wallet/activities List wallet transactions. ```text theme={null} GET /v1/wallet/activities ``` List the wallet's top-up and credit history with cursor-based pagination — prepaid top-ups and credits (promotional, manual). Run charges are not included; see [`GET /v1/runs`](/docs/api/runs/list) for per-run costs. ## Headers | Header | Required | Description | | ---------------- | -------- | -------------------------------------------------------- | | `Authorization` | Yes | `Bearer ` | | `x-workspace-id` | No | Only needed with OAuth/JWT tokens without an org context | ## Query Parameters | Parameter | Type | Default | Description | | --------- | ------ | ------- | -------------------- | | `limit` | number | 25 | Maximum items (1–25) | | `cursor` | string | — | Pagination cursor | ## 200 OK | Field | Type | Description | | ------------------- | ------------------- | ----------------------------------------- | | `items` | array | Activity items | | `items[].id` | string | Activity ID | | `items[].type` | string \| undefined | Activity type (e.g. `"Top-Up"`) | | `items[].amount` | number | Amount in dollars (non-negative float) | | `items[].currency` | string | ISO currency code | | `items[].expiredAt` | string \| undefined | When the activity expires (if applicable) | | `items[].createdAt` | string \| undefined | When the activity was created | | `cursor` | string \| null | Next-page cursor. `null` if last page | ```json theme={null} { "items": [ { "id": "act_01HXYZ...", "type": "Top-Up", "amount": 10, "currency": "USD", "createdAt": "2026-03-28T10:30:15.000Z" } ], "cursor": null } ``` ## 503 Service Unavailable Returned when the wallet is not active. # Get Balance Source: https://monid.ai/docs/api/wallet/balance Get the current wallet balance. ```text theme={null} GET /v1/wallet/balance ``` Get the current wallet balance for your workspace. ## Headers | Header | Required | Description | | ---------------- | -------- | -------------------------------------------------------- | | `Authorization` | Yes | `Bearer ` | | `x-workspace-id` | No | Only needed with OAuth/JWT tokens without an org context | ```bash curl theme={null} curl "https://api.monid.ai/v1/wallet/balance" \ -H "Authorization: Bearer monid_live_..." ``` ## 200 OK | Field | Type | Description | | --------- | ------ | --------------------------------------------------------------------------------- | | `balance` | object | Available balance as `{ "value": number, "currency": "USD" }`. It may be negative | | `held` | object | Funds held for in-flight runs, same shape | ```json theme={null} { "balance": { "value": 2.85, "currency": "USD" }, "held": { "value": 0.10, "currency": "USD" } } ``` ## 503 Service Unavailable Returned with a `walletStatus` field when the wallet is not active. # monid discover Source: https://monid.ai/docs/cli/discover Search for data endpoints using natural language. Search for data endpoints using natural language. ## Usage ```bash theme={null} monid discover -q [--limit ] [--json] ``` ## Flags | Flag | Type | Required | Description | | --------------------- | ------- | -------- | --------------------------------------------- | | `-q, --query ` | string | Yes | A short natural language search query | | `--limit ` | number | No | Maximum number of results (default 5, max 40) | | `-j, --json` | boolean | No | Output raw JSON | ## Examples ```bash theme={null} # Search for Twitter-related endpoints monid discover -q "twitter posts" # Search with a limit monid discover -q "linkedin profiles" --limit 3 # Get raw JSON output monid discover -q "amazon product reviews" --json ``` ## Output Returns a list of endpoints matching the query: ```text theme={null} Provider Endpoint Price Description apify /apidojo/tweet-scraper $0.003/call Scrape tweets by search... apify /apidojo/twitter-user-scraper $0.003/call Scrape Twitter user pro... ``` With the `--json` flag, the full JSON response is printed: ```json theme={null} { "results": [ { "provider": "apify", "providerName": "Apify", "endpoint": "/apidojo/tweet-scraper", "description": "Scrape tweets by search terms, hashtags, or user handles", "score": 0.87, "tags": ["twitter", "social-media"], "scoreBreakdown": { "querierScore": 0.82 }, "price": { "type": "PER_CALL", "amount": { "value": 0.003, "currency": "USD" } } } ], "query": "twitter posts", "count": 2 } ``` ## Tips * **Keep queries short and focused.** Noun phrases like `"twitter posts"` or `"amazon product prices"` work better than full sentences. * **Break complex requests into smaller pieces.** If you need data from multiple sources, discover each separately. * **The endpoint catalog grows continuously.** Always discover rather than assuming what's available. ## Next Steps After discovering endpoints, use [`monid inspect`](/docs/cli/inspect) to see the full input schema before running. # examples Source: https://monid.ai/docs/cli/examples Complete end-to-end examples using the Monid CLI. Complete end-to-end examples using the Monid CLI. ```bash theme={null} # 1. Discover Twitter endpoints monid discover -q "twitter posts" # 2. Inspect the tweet scraper to see input schema monid inspect -p apify -e /apidojo/tweet-scraper # 3. Run with a small limit monid run -p apify -e /apidojo/tweet-scraper \ -i '{"searchTerms":["AI"],"maxItems":10}' # → Run ID: 01HXYZ... # 4. Get the results monid runs get -r 01HXYZ... -o ai_tweets.json ``` Break the request into separate queries — one per platform. ```bash theme={null} # 1. Discover endpoints for each platform monid discover -q "twitter posts" monid discover -q "linkedin posts" # 2. Inspect each to learn their input schemas monid inspect -p apify -e /apidojo/tweet-scraper monid inspect -p apify -e /harvestapi/linkedin-post-search # 3. Run both monid run -p apify -e /apidojo/tweet-scraper \ -i '{"searchTerms":["AI"],"maxItems":10}' # → Run ID: 01H_TW... monid run -p apify -e /harvestapi/linkedin-post-search \ -i '{"keywords":"AI","maxResults":10}' # → Run ID: 01H_LI... # 4. Get results for each monid runs get -r 01H_TW... -o twitter_ai.json monid runs get -r 01H_LI... -o linkedin_ai.json ``` ```bash theme={null} # 1. Discover Google Maps endpoints monid discover -q "google maps reviews" # 2. Inspect the scraper monid inspect -p apify -e /damilo/google-maps-scraper # 3. Create an input file for complex parameters cat > params.json << 'EOF' { "searchStringsArray": ["restaurants in San Francisco"], "maxReviews": 10, "language": "en" } EOF # 4. Run with input from file monid run -p apify -e /damilo/google-maps-scraper -i @params.json # → Run ID: 01HGEO... # 5. Get the results monid runs get -r 01HGEO... -o reviews.json ``` # monid inspect Source: https://monid.ai/docs/cli/inspect Get full details for a specific data endpoint. Get full details for a specific data endpoint, including input schema, pricing, and documentation. ## Usage ```bash theme={null} monid inspect -p -e [--json] ``` ## Flags | Flag | Type | Required | Description | | --------------------------- | ------- | -------- | ---------------------------------------------- | | `-p, --provider ` | string | Yes | Provider slug (e.g., `apify`) | | `-e, --endpoint ` | string | Yes | Endpoint path (e.g., `/apidojo/tweet-scraper`) | | `-j, --json` | boolean | No | Output raw JSON | ## Examples ```bash theme={null} # Inspect a Twitter scraper monid inspect -p apify -e /apidojo/tweet-scraper # Inspect a Google Maps scraper monid inspect -p apify -e /damilo/google-maps-scraper # Get raw JSON output monid inspect -p apify -e /apidojo/tweet-scraper --json ``` ## Output The inspect command displays: * **Provider and endpoint name** * **Description** — what the endpoint does * **Summary** — detailed overview (when available) * **Input schema** — JSON schema of accepted parameters * **Pricing** — type (PER\_CALL or PER\_RESULT), amount, flat fee, and notes * **Documentation URL** — link to the provider's docs * **Usage examples** — ready-to-use CLI and API commands Example output: ```text theme={null} Provider: apify Endpoint: /apidojo/tweet-scraper Description: Scrape tweets by search terms, hashtags, or user handles Price: Type: PER_CALL Amount: $0.003 Input Schema: { "searchTerms": ["string"], "maxItems": "number", "sort": "string" } Documentation: https://apify.com/apidojo/tweet-scraper Usage: CLI: monid run -p apify -e /apidojo/tweet-scraper -i '{"searchTerms":["AI"]}' API: POST /v1/run {"provider":"apify","endpoint":"/apidojo/tweet-scraper","input":{...}} ``` Always inspect before running. The input schema tells you exactly what parameters the endpoint accepts — never guess. ## Next Steps After inspecting an endpoint, use [`monid run`](/docs/cli/run) to execute it. # monid keys activate Source: https://monid.ai/docs/cli/keys/activate Switch the active API key. Switch the active API key. ## Usage ```bash theme={null} monid keys activate --label ``` ## Flags | Flag | Type | Required | Description | | --------------------- | ------ | -------- | ---------------------------- | | `-l, --label