API reference
Use the Fetchply API with your own API keys, or integrate through the widget, Functions, and webhooks.
Fetchply has a customer API under /api/v1. Authenticate every request with an API key you create in the dashboard. Internal dashboard routes remain unsupported and can change without notice; build only against /api/v1.
Create an API key
- In the dashboard, open API keys in the sidebar.
- Choose Create key, give it a name, and pick the permissions it needs.
- Copy the key when it is shown. It appears once and cannot be retrieved again.
If a key is lost or no longer needed, revoke it from the same page. Revoking takes effect immediately and cannot be undone; create a new key to restore access. An account can hold up to 20 active keys; if creating a key fails with a limit message, revoke one you no longer use first.
Treat API keys like passwords. Use them from your own server or tools, never inside a public website or app where visitors could read them.
Authentication
Send the key as a bearer token on every request:
curl https://fetchply.com/api/v1/agents \
-H "Authorization: Bearer fp_live_YOUR_KEY"A missing or invalid key returns 401. A key that lacks the permission for an endpoint returns 403.
Endpoints
Each endpoint has its own reference page in the sidebar with parameters, response fields, and examples. Every page includes a playground: paste your own API key into the Authorization field, fill in the parameters, and send a real request to your account right from the docs.
| Method | Path | Permission | Purpose |
|---|---|---|---|
| GET | /api/v1/agents | read:agents | List the agents the key can access |
| GET | /api/v1/agents/{id} | read:agents | Read one agent |
| GET | /api/v1/agents/{id}/overview | read:analytics | One call answering "how is my agent doing" |
| GET | /api/v1/agents/{id}/analytics | read:analytics | Top questions, unanswered queries, satisfaction, and visitor locations |
| GET | /api/v1/agents/{id}/unanswered-questions | read:analytics | Questions the agent could not answer |
| GET | /api/v1/agents/{id}/conversations | read:conversations | List conversations, newest first |
| GET | /api/v1/conversations/{id} | read:conversations | One conversation with its transcript |
| GET | /api/v1/agents/{id}/sources | read:sources | List training sources with their indexing status |
| GET | /api/v1/agents/{id}/sources/{sourceId} | read:sources | Read one source, including a text snippet's stored content |
| GET | /api/v1/agents/{id}/training-status | read:sources | Live training progress for an agent |
| GET | /api/v1/agents/{id}/knowledge/search | read:knowledge | Search what the agent knows and get the most relevant passages |
| GET | /api/v1/agents/{id}/qa-pairs | read:qa | List curated Q&A pairs |
| GET | /api/v1/agents/{id}/leads | read:leads | List captured leads, newest first |
| GET | /api/v1/agents/{id}/leads/{leadId} | read:leads | Read one captured lead |
| GET | /api/v1/usage | read:usage | Plan usage and message credits |
| POST | /api/v1/agents/{id}/sources | write:sources | Add a URL or text snippet to the agent's knowledge |
| POST | /api/v1/agents/{id}/sources/files | write:sources | Upload a document file to the agent's knowledge |
| PATCH | /api/v1/agents/{id}/sources/{sourceId} | write:sources | Update a text snippet's title or content in place |
| DELETE | /api/v1/agents/{id}/sources/{sourceId} | write:sources | Delete a source and everything indexed from it |
| POST | /api/v1/agents/{id}/retrain | write:sources | Refresh the agent's knowledge from its website |
| POST | /api/v1/agents/{id}/qa-pairs | write:qa | Create a Q&A pair |
| PATCH | /api/v1/agents/{id}/qa-pairs/{pairId} | write:qa | Update or disable a Q&A pair |
| DELETE | /api/v1/agents/{id}/qa-pairs/{pairId} | write:qa | Delete a Q&A pair |
| POST | /api/v1/agents/{id}/chat | write:chat | Send a message to an agent and get its reply |
A machine-readable OpenAPI description is available at /api/v1/openapi.json.
The overview, analytics, and unanswered-questions endpoints accept ?period=7d, 30d (default), or 90d. List endpoints are paged with limit (up to 100) and offset. Conversation lists can be filtered by channel or state=open|resolved; source lists by type=url|text|file; Q&A lists by kind=qa|media; lead lists by an email substring and an inclusive startDate/endDate range (YYYY-MM-DD). Conversation and lead data never includes visitor network details, and conversation transcripts never include your team's private notes.
Keep an agent's knowledge fresh
The sources and training endpoints let you sync an agent's knowledge from your own systems, for example after publishing a help article or updating a price list:
# Add a page the agent should learn
curl -X POST https://fetchply.com/api/v1/agents/AGENT_ID/sources \
-H "Authorization: Bearer fp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "url", "url": "https://acme.com/pricing"}'
# Or push text directly
curl -X POST https://fetchply.com/api/v1/agents/AGENT_ID/sources \
-H "Authorization: Bearer fp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "text", "title": "Refund policy", "content": "Refunds are available within 30 days..."}'
# Or upload a document file
curl -X POST https://fetchply.com/api/v1/agents/AGENT_ID/sources/files \
-H "Authorization: Bearer fp_live_YOUR_KEY" \
-F "[email protected]"
# Edit a text snippet in place (title, content, or both)
curl -X PATCH https://fetchply.com/api/v1/agents/AGENT_ID/sources/SOURCE_ID \
-H "Authorization: Bearer fp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Refunds are available within 45 days..."}'Adding a source answers immediately and indexes in the background; watch GET /agents/{id}/sources until the source's status becomes indexed (or failed, with the reason in errorMessage). POST /agents/{id}/retrain re-reads every known page and discovers new ones on the site; poll GET /agents/{id}/training-status for phase and page progress. Useful to know:
- Only one training job runs per agent at a time. Starting another while one is active returns
409; wait for it to finish or watchtraining-status. - Text snippets can hold up to 1 MB of plain text; URLs must be public pages.
- Only text snippets can be edited in place.
GET /agents/{id}/sources/{sourceId}returns a snippet's stored text incontent, so you can read, adjust, and send it back; fields you omit from the PATCH keep their current values. Refresh a URL source by retraining, and a file source by uploading the new file. - File uploads accept PDF, DOCX, PPTX, CSV, XLS/XLSX, TXT, Markdown, HTML, or JSON documents up to 10 MB, sent as a
filefield in amultipart/form-databody. - If adding sources returns
403withtraining_limit_exceeded, the account reached its plan's training data limit; remove sources or upgrade. - Deleting a source removes everything the agent learned from it. This cannot be undone.
Search what an agent knows
GET /api/v1/agents/{id}/knowledge/search looks up a question in the agent's trained knowledge and returns the most relevant passages, best match first, together with the title and address of the page or document each one came from:
curl "https://fetchply.com/api/v1/agents/AGENT_ID/knowledge/search?query=refund%20policy" \
-H "Authorization: Bearer fp_live_YOUR_KEY"It uses the same lookup the agent performs when answering a visitor, so it is the quickest way to check whether the agent learned something, without starting a conversation or using message credits. Useful to know:
queryis required; phrase it like a visitor question for the best matches.limitcaps the number of passages (up to 10, default 5).- An agent that has not finished training yet returns an empty list. Add sources or retrain, wait for indexing to finish, and search again.
- An empty list on a trained agent means nothing relevant was found; that topic is a good candidate for a new source or Q&A pair.
Manage Q&A pairs
Q&A pairs are curated answers the agent serves verbatim, and the API can manage them end to end: list them, create new ones, update or disable them, and delete them. A natural loop is to read unanswered-questions and turn the gaps into new pairs. Changes are re-indexed in the background and start matching shortly after; text-only pairs are created through the API, while pairs with images or video are managed in the dashboard.
Chat with an agent
POST /api/v1/agents/{id}/chat sends a message and returns the agent's answer as JSON, so you can put your agent inside your own product, backend, or automation tool:
curl -X POST https://fetchply.com/api/v1/agents/AGENT_ID/chat \
-H "Authorization: Bearer fp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "What are your opening hours?"}'The response contains the reply, the sources it was grounded in, and a sessionId. Send the same sessionId in your next request to continue the conversation; omit it to start a new one. Useful to know:
- Each delivered message uses one message credit from your plan, the same as widget messages. When credits run out the endpoint returns
402. - Conversations show up in your dashboard Inbox under the API channel, so you can review them like any other conversation.
- Retries are safe: pass a
clientMessageIdof your choosing and repeated sends of the same message never use extra credits. - Replies are markdown formatted. The endpoint answers with text only; it does not send files or images.
A quick first test: open the List agents page from the sidebar, paste your key, and send the request. Copy an agent id from the response and use it on the other endpoint pages.
Connect an AI assistant (MCP)
Fetchply is also an MCP server, so AI assistants like Claude and Cursor can work with your agents directly: list them, check how they perform, surface unanswered questions, search what they know, read conversations and leads, monitor usage, and (with write permissions) manage training sources and Q&A pairs. See Connect an AI assistant for setup in each client, the available tools, and troubleshooting.
Rate limits
Each key allows 60 requests per minute by default. Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. When the limit is exceeded, requests return 429 with a Retry-After header; wait that many seconds before retrying.
Errors
Errors are JSON documents with a stable type, a human-readable title, and the HTTP status:
{ "type": "insufficient_scope", "title": "Key lacks required permissions", "status": 403 }Troubleshooting
- Every request returns 401. The key was mistyped, revoked, or expired. Check for extra spaces in the header and confirm the key still appears as active on the API keys page; if not, create a new one.
- A request returns 403. The key does not have the permission that endpoint requires. Create a new key with the right permissions selected.
- An agent or conversation returns 404. The ID is wrong, the item was deleted, or the key is restricted to other agents. List
/api/v1/agentsto see what the key can access. - Unanswered questions return 403. That data is part of advanced analytics, which your current plan does not include. The response names the plan that does. The analytics endpoint still works on every plan; its advanced sections are empty and flagged with
advancedAnalytics: false. - Adding a source or retraining returns 409. A training job is already running for that agent. Poll
training-statusand try again when it finishes. - A source stays in
processingorpending. Indexing runs in the background and large pages can take a few minutes. If it ends asfailed,errorMessageexplains why; fix the source and add it again. - Adding a URL returns 400. The address is not a public web page. Private, internal, and localhost addresses are not accepted.
- Updating a source returns 400. Only text snippets can be edited in place. Refresh a URL source with retraining, or replace a file source by uploading the new document and deleting the old one.
- Uploading a file returns 400 or 413. The file type is unsupported or the file is over 10 MB. Check the supported formats above and send the document as a
filefield in amultipart/form-databody. - A Q&A change returns 503. The change was saved but indexing could not be scheduled right away. It is indexed with the next Q&A change, or retry in a moment.
- Requests return 429. The key hit its per-minute limit. Respect the
Retry-Afterheader, or spread requests out.
Other integration surfaces
Widget installation
Embed floating or inline chat and use supported data attributes.
Functions
Let the agent call your API with controlled inputs and auth.
Webhooks
Receive selected Fetchply events as JSON POST requests.
Widget data attributes
After the floating widget script loads:
data-fetchply-openopens chat from your own button.data-fetchply-message="..."opens chat and sends the supplied message.
Copy the exact install script from Deploy. The public agent ID may appear in client code. API keys and integration secrets must not.