Skip to main content

Manage AI Employee Knowledge

An AI Employee is an AI assistant. It operates in the account of a business. It answers questions, prepares replies, and helps the staff and the customers of that business. An AI Employee is only as good as its knowledge. To teach an AI Employee, give it knowledge sources. A knowledge source is one piece of reference material. Examples: a product FAQ, a returns policy, a price list, an employee handbook.

It is important to know how the AI Employee uses its knowledge. The AI Employee does not read all of its knowledge base at one time. When a person speaks with the AI Employee, it does a semantic search of the knowledge sources. The search finds only the small number of passages that are most applicable to the question. Because of this, knowledge is a good location for facts. Examples: policies, price lists, FAQs, product data. Knowledge is not a good location for instructions about the behavior of the AI Employee ("always greet customers with...", "never discuss competitors"). The AI Employee obeys such an instruction only if the search finds it. Put behavior rules in the configuration of the AI Employee, not in its knowledge.

This guide is for teams that keep their reference material in a different system. Examples: a CMS, a help desk, a shared drive, your product database. This guide shows how to keep the AI Employees in Vendasta synchronized with that system automatically. Manual work in the dashboard is not necessary. After you complete this guide, you can:

  • find the businesses and the AI Employees in your Vendasta account,
  • push knowledge to an AI Employee as text or as a file,
  • make sure that the knowledge completed its processing,
  • update or remove the knowledge that you pushed before, and
  • remove all the knowledge that you added, when a customer offboards.
Before you start

This guide is for developers. You will send HTTP requests to the Vendasta API. Experience with the Vendasta platform is not necessary. But you must know how to send authenticated HTTP requests. Applicable tools include curl, Postman, or a small script.


The one rule that keeps this integration safe

Read this section first. It is the most important idea in this guide.

The knowledge base of a business is a shared space. It can contain:

  • knowledge that your integration created,
  • knowledge that a person created manually in the Vendasta dashboard,
  • a Business Profile source that the platform creates and keeps automatically, and
  • knowledge that a partner shared with the account (see Knowledge you cannot manage).

When you create a knowledge source, the API returns a knowledgeSourceId. This id is your only reliable handle for the source that you created. The rules that follow all come from this fact:

  • Keep each knowledgeSourceId that the API returns. Keep it together with the related record in your own system. Examples: the help-desk article id, the file path.
  • You must supply the stored id to update knowledge. This applies to text and to files. The server cannot find the source that you created before. If you push again without the id, you always create a new, duplicate source. This occurs also when the name or the file name is the same.
  • Change only the ids that you created. Do not update or remove an id that you do not know. The API rejects changes to the platform-managed sources (see Knowledge you cannot manage). The API does not protect the sources that a person created. The API cannot tell your sources from theirs. If you change or remove their sources, the AI Employee will not operate correctly for the business.
  • Recovery is possible if you lose an id or create a duplicate by accident. List the knowledge base and compare the names or the file names. Then update or delete by id.
  • Offboarding is the same procedure in reverse. List the knowledge base. Then remove the ids that your integration created. Do not remove other ids.

Keep a small mapping table in your own database from the start: your_record_id → vendasta_knowledge_source_id. This table keeps the integration simple. Without this table, you will create duplicates that you cannot find safely.


Step 1: Get an access token

Each request must contain a service-account access token. A service account belongs to your organization, not to a person. This is the correct type of account for an unattended integration.

Do the platform procedures to create the service account and to get a token for its credentials.

When you request the token, ask for the scopes that this guide uses. A scope is a permission that is attached to the token:

ScopePermits you to
businessList the businesses (account groups) in your account
ai-assistantFind the AI Employees on an account
knowledgeRead and write knowledge (list, upsert, status, upload, remove)

Send the token in an Authorization header on each request:

Authorization: Bearer <your access token>

In this guide, replace each Bearer <Access Token ...> with the token that you got here.

note

Tokens expire. A long-running integration must request a new token before the current token expires. Do not use one token permanently.


Step 2: Find the businesses in your account

Knowledge always belongs to one business. In Vendasta, a business is an account group. Its id has the format AG-XXXXXXXXXX. Each knowledge request must contain this id.

If your system already keeps the account group ids, go to Step 3. If not, get the ids with the List Business Locations API. Set your partner id in the filter[businessPartner.id] query parameter. The partner id is the short identifier of your organization in Vendasta, for example ABC. This parameter is mandatory.

curl -g 'https://prod.apigateway.co/platform/businessLocations?filter[businessPartner.id]=ABC&page[limit]=25' \
-H 'Authorization: Bearer <Access Token with "business" scope>'

The response contains one page of businesses in data. The id of each entry is the account group id that you will use later.

{
"links": {
"first": "https://prod.apigateway.co/platform/businessLocations?filter[businessPartner.id]=ABC&page[cursor]=&page[limit]=25",
"next": "https://prod.apigateway.co/platform/businessLocations?filter[businessPartner.id]=ABC&page[cursor]=MjU=&page[limit]=25"
},
"data": [
{
"type": "businessLocations",
"id": "AG-1234567",
"attributes": {
"name": "Company Example"
}
}
]
}

If your account has more businesses than one page can hold, the response contains a links.next URL. Send a GET request to that URL, with your Authorization header, to get the subsequent page. Continue until a response does not contain a links.next.


Step 3: Find the AI Employees on an account

An account can have more than one AI Employee. Knowledge is attached to one specified AI Employee. Each AI Employee has an assistant id with the format ASSISTANT-XXXX.

Use List Assistants to list the AI Employees on an account group. This request, and all the requests after it, go to the gRPC gateway at https://prod.apigateway.co/grpc. These endpoints use POST with a JSON body.

curl -X POST 'https://prod.apigateway.co/grpc/v1/assistants/list' \
-H 'Authorization: Bearer <Access Token with "ai-assistant" scope>' \
-H 'Content-Type: application/json' \
-d '{"accountGroupId": "AG-1234567"}'

The response lists the AI Employees on the account. Record the assistantId. You will use this value when you attach knowledge.

{
"assistants": [
{
"assistantId": "ASSISTANT-A1B2",
"assistantType": "receptionist",
"name": "Front Desk"
}
],
"pagingMetadata": {
"hasMore": false,
"nextCursor": "",
"totalResults": "1"
}
}
Use the id exactly as returned

The Knowledge API accepts only the full ASSISTANT-XXXX format. The API rejects all other formats. Examples of rejected formats: the id without its ASSISTANT- prefix, and internal application ids that start with APP-. Do not construct assistant ids yourself. Always copy them from this endpoint.

The default AI Employees have stable ids that you can identify easily. Examples: ASSISTANT-chat-receptionist (the Chat Receptionist) and ASSISTANT-voice-receptionist (the Voice Receptionist). Different accounts have different AI Employees. Always use this endpoint to make sure which AI Employees are present. Do not make an assumption.

The pages of this endpoint operate the same as the pages of the knowledge endpoints. See Paging through long lists below. The same loop applies here.


Step 4: Add knowledge as text

The most simple knowledge source is a piece of text. Examples: an FAQ answer, a policy paragraph, a set of talking points. Use Upsert Knowledge to create one. Set the text content. Give the source a name that a person can read. Set assistantId to connect the source to the applicable AI Employee. The maximum length of the text is 100,000 characters (see Limits). For material that is longer, use a file.

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/upsert' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"assistantId": "ASSISTANT-A1B2",
"name": "Returns policy",
"description": "Our 30-day returns policy, synced from the help center.",
"content": {
"text": {
"text": "Customers may return unused items within 30 days for a full refund..."
}
}
}'

This request did not contain a knowledgeSourceId. Because of this, the request creates a new source. The response gives you its id:

{
"knowledgeSourceId": "KS-7f3c1a90"
}

Keep KS-7f3c1a90 now. Map it to the related record in your own system. You will use it to update or remove this source later. There is no other reliable method to find the source again. (See the one rule.)

How the connection to an AI Employee operates. When you set assistantId on an upsert, the API adds a link between the source and that AI Employee. Links are additive and idempotent. If you send the same link again, nothing changes. If you do not set assistantId on a subsequent update, the current links of the source stay the same. Upsert never removes a link. To disconnect a source from an AI Employee, use Remove Knowledge in unlink mode.


Step 5: Add knowledge as a file

Much reference material starts as a document. Examples: a PDF handbook, a spreadsheet price list, a Word policy. You do not send files in the request body. There are three steps. It helps to know the reason first:

  1. Ask Vendasta for a location for the file. Use Create Knowledge File Upload. The response contains a temporary, safe upload URL and an upload handle.
  2. Send the bytes of the file directly to that URL with an HTTP PUT. The bytes go directly to storage. They do not go through the API.
  3. Tell the AI Employee about the uploaded file. Use Upsert Knowledge again. In this request, refer to the upload handle from step 1.

The file becomes knowledge only at step 3. Steps 1 and 2 only put the bytes in the correct location.

5a. Request an upload URL

Supply the file name, with its extension, and the MIME type of the file. The API accepts these formats: PDF, Word (.docx), PowerPoint (.pptx), Excel (.xlsx/.xls), images (.jpg, .png, processed with OCR), HTML, plain text, Markdown, CSV, and JSON/JSONL.

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/file-upload' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"fileName": "handbook.pdf",
"contentType": "application/pdf"
}'

The response contains all that you need for the subsequent step:

{
"uploadUrl": "https://storage.googleapis.com/...&X-Goog-Signature=...",
"uploadHandle": "uh_0c1ffbf9...",
"requiredHeaders": {
"Content-Type": "application/pdf",
"X-Goog-Content-Length-Range": "0,52428800"
},
"expiresAt": "2026-07-23T19:30:00Z"
}
  • uploadUrl is the location for the PUT of the bytes in step 5b.
  • uploadHandle is the token that you refer to in step 5c. It is connected to this account group and to your credentials. It expires at expiresAt.
  • requiredHeaders are the headers that you must send with the PUT, with no changes. They are part of the signed URL. Storage rejects a PUT if its headers do not agree with the URL.

5b. Upload the bytes

PUT the unchanged file to uploadUrl. Send each header from requiredHeaders exactly as given. This request goes to Google Cloud Storage, not to prod.apigateway.co. Do not send an Authorization header. The signed URL is the authorization.

curl -X PUT \
-H "Content-Type: application/pdf" \
-H "X-Goog-Content-Length-Range: 0,52428800" \
--data-binary @handbook.pdf \
"https://storage.googleapis.com/...&X-Goog-Signature=..."

An upload that is successful returns 200 OK with an empty body. The maximum file size is 50 MB. Do the PUT before expiresAt. Storage rejects a URL that expired. Then you must request a new URL.

5c. Change the uploaded file into knowledge

Use Upsert Knowledge with a file content block that refers to the uploadHandle. As in Step 4, a request without a knowledgeSourceId creates a new source.

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/upsert' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"assistantId": "ASSISTANT-A1B2",
"name": "Employee handbook",
"content": {
"file": {
"uploadHandle": "uh_0c1ffbf9...",
"fileName": "handbook.pdf",
"mimeType": "application/pdf"
}
}
}'

The response returns a knowledgeSourceId, the same as for text. Keep it. The handle is for one ingest only, and it expires. The knowledgeSourceId is the permanent handle that you keep.


Step 6: Make sure that the knowledge is ready

When you create a source, processing starts in the background. The AI Employee can not use the content until processing completes. Use Get Knowledge Status, with the knowledgeSourceId that you kept, to monitor the progress.

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/status' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"knowledgeSourceId": "KS-7f3c1a90"
}'
{
"status": {
"state": "TRAINING_STATE_IN_PROGRESS",
"totalUnits": "12",
"completedUnits": "5",
"errorCode": "TRAINING_ERROR_CODE_INVALID"
}
}

Make your decision on the state field:

stateMeaning
TRAINING_STATE_QUEUEDThe API accepted the source. Processing did not start.
TRAINING_STATE_IN_PROGRESSProcessing is in operation. completedUnits / totalUnits show the progress.
TRAINING_STATE_DONEThe source is ready. The AI Employee can use it.
TRAINING_STATE_ERROREDProcessing failed. Read errorCode for the cause.

errorCode has a meaning only when state is TRAINING_STATE_ERRORED. Ignore it in the other states. Two file-processing failures are possible. TRAINING_ERROR_CODE_LARGE_FILE_CONTENT: the content is too large for processing. TRAINING_ERROR_CODE_UNPROCESSABLE_CONTENT: the parse of the content failed, for example because the file is defective or empty.

To wait until the source is ready, poll. Send this request again until state is TRAINING_STATE_DONE or TRAINING_STATE_ERRORED. Do not send the requests continuously. Wait some seconds between the requests.


Step 7: Update existing knowledge

When your source material changes, push the change to the same source. To do this, send the stored knowledgeSourceId. The API then updates the source that exists. It does not create a duplicate.

To update text:

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/upsert' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"knowledgeSourceId": "KS-7f3c1a90",
"content": {
"text": {
"text": "Customers may return unused items within 45 days for a full refund..."
}
}
}'

The update of a file uses the same method. Do the file upload procedure again to get a new uploadHandle. Then upsert with the stored knowledgeSourceId set. The new file replaces the current file of the source.

Know these facts when you update:

  • The id is mandatory for an update. An upsert without a knowledgeSourceId always creates a new source. This occurs also when the name or the file name is equal to a source that exists. The server does not remove duplicates. A push without the id is the usual cause of accidental duplicates.
  • The kind of a source is permanent. A source that you created as text stays text. A source that you created from a file stays a file. The content that you send on an update must agree with the kind of the source.
  • Fields that you do not send stay the same. Send no name to keep the current name. Send no content to change only the links (see below). Send no assistantId to keep the current AI Employee links.

Step 8: Recover a lost id, or clean up a duplicate

Recovery is necessary if a script stops between the creation of a source and the storage of its id. It is also necessary if you find a duplicate. Use List Knowledge for the recovery. It returns each knowledge source in the knowledge base of the account.

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/list' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{"accountGroupId": "AG-1234567"}'
{
"knowledgeSources": [
{
"knowledgeSourceId": "KS-7f3c1a90",
"name": "Returns policy",
"fileName": "",
"configType": "KNOWLEDGE_CONFIG_TYPE_CUSTOM_DATA",
"status": { "state": "TRAINING_STATE_DONE" },
"created": "2026-07-23T18:00:00Z",
"updated": "2026-07-23T18:05:00Z"
},
{
"knowledgeSourceId": "KS-11aa22bb",
"name": "Employee handbook",
"fileName": "handbook.pdf",
"configType": "KNOWLEDGE_CONFIG_TYPE_FILE",
"status": { "state": "TRAINING_STATE_DONE" },
"created": "2026-07-23T18:10:00Z",
"updated": "2026-07-23T18:12:00Z"
}
],
"pagingMetadata": {
"hasMore": false,
"nextCursor": "",
"totalResults": "2"
}
}

To find a source with a lost id, compare the name that you gave it (text sources) or the fileName (file sources). When you have the knowledgeSourceId, you can update the source or remove the duplicate.

You can also limit the list to one AI Employee. To do this, add an assistantId to the request body. The response then contains only the sources with a link to that AI Employee.

info

configType shows the kind of each source. KNOWLEDGE_CONFIG_TYPE_CUSTOM_DATA: text that you supplied. KNOWLEDGE_CONFIG_TYPE_FILE: an uploaded file. KNOWLEDGE_CONFIG_TYPE_WEBSITE: content from a website. KNOWLEDGE_CONFIG_TYPE_BUSINESS_PROFILE: the platform-managed Business Profile. The list returns all of these kinds. This includes the sources that a person created in the dashboard and the Business Profile. Compare the list with your own stored ids. Manage only the sources that you created.


Step 9: Remove knowledge, and offboard

Remove Knowledge does one of two different things. You must select one with a mode. The API does not select for you.

Unlink disconnects a source from one or more AI Employees. The source itself stays. Use this mode when one AI Employee must stop the use of a piece of knowledge, but other AI Employees continue to use it.

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/remove' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"knowledgeSourceId": "KS-7f3c1a90",
"unlink": {
"assistantIds": ["ASSISTANT-A1B2"]
}
}'

Delete removes the source fully.

curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/remove' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"knowledgeSourceId": "KS-7f3c1a90",
"deleteSource": {}
}'

deleteSource is an empty object. Its presence is the instruction to delete. Send exactly one of unlink or deleteSource in each request.

warning

A deletion has more than one internal step. If a remove request fails after a part of the steps, do not send the same request again immediately. First, list the knowledge base to see the current state. Then act on the sources that are there.

Offboarding a customer

When your management of a business stops, remove only the sources that your integration created:

  1. Use List Knowledge for the account group. Get each page (see below).
  2. Find each returned source with a knowledgeSourceId that is in your own mapping table. For each one, use Remove Knowledge with deleteSource.
  3. Ignore each id that you do not know. The sources that a person created are not yours. The API cannot tell your sources from theirs. Only your mapping table can. The API rejects the removal of platform-managed sources (see Knowledge you cannot manage).

This is the full offboarding loop: list, then remove your own ids.


Paging through long lists

List Knowledge, List Assistants, and each other gRPC-gateway list use one paging contract. Read this section carefully. The stop condition that seems natural is not correct.

Each list response contains pagingMetadata:

"pagingMetadata": {
"hasMore": true,
"nextCursor": "eyJvZmZzZXQiOjEwMH0=",
"totalResults": "0"
}

To read each page:

  1. Send the first request with no cursor.
  2. If hasMore is true, send the subsequent request. Set pagingOptions.cursor to the nextCursor from the response.
  3. Continue until hasMore is false. The last page contains no nextCursor.
curl -X POST 'https://prod.apigateway.co/grpc/v1/knowledge/list' \
-H 'Authorization: Bearer <Access Token with "knowledge" scope>' \
-H 'Content-Type: application/json' \
-d '{
"accountGroupId": "AG-1234567",
"pagingOptions": {
"cursor": "eyJvZmZzZXQiOjEwMH0=",
"pageSize": "50"
}
}'
Stop on hasMore, not on the page size

A page can contain fewer items than you requested and have hasMore: true at the same time. If you stop at the first short page, you will miss knowledge sources with no warning. The only correct stop signal is hasMore: false. Also, do not trust totalResults. It is 0 on APIs that do not compute a total.


Knowledge you cannot manage

Two kinds of knowledge are intentionally not manageable through this API.

Platform-managed sources. The platform automatically creates a Business Profile source on each account, and keeps it correct. Where configured, it also creates a business-website source. These sources do appear in List Knowledge. Their ids start with KS-business-profile- or KS-business-website-. This lets you see the full working set of the AI Employee. But you cannot change these sources. The API rejects an upsert or a remove (delete or unlink) against one of them. The error is InvalidArgument, and it says that the source is platform-managed. No action from you is necessary. The API enforces this.

Knowledge that a partner shared with the account. A partner can share knowledge with the account. This knowledge was not created on the account itself. Your integration cannot touch it at all. An integration can never change content that a different party owns. The effects are:

  • List Knowledge does not show shared sources. They do not appear in the list. Because of this, the offboarding loop never sees an id that it must not touch.
  • A change attempt returns NotFound. This occurs if you use the id of a shared source in an upsert, status, or remove request. This is the intended result. It is not a defect, and the source is not missing.

All other parts of this guide (text, files, updates, removal) apply to the sources that exist directly on the account. These are the sources that your integration creates, the sources that persons create in the dashboard, and the two platform-managed sources above.


Limits

The API applies these limits. In this table, "write requests" means Upsert Knowledge, Create Knowledge File Upload, and Remove Knowledge, together.

LimitValue
Write requests, for each account group10 requests per minute
Write requests, for each partner (all account groups together)100 requests per minute
Text content100,000 characters
name500 characters
description2,000 characters
fileName255 characters
assistantIds in one Remove Knowledge request100 ids
File size50 MB

Know these facts about the limits:

  • The rate limit applies only to the write endpoints. It does not apply to List Knowledge, Get Knowledge Status, or List Assistants.
  • Each account group has its own write budget. The partner-wide ceiling applies to all your account groups together. This lets you push knowledge to many account groups at the same time, up to the ceiling. Writes to your partner-level knowledge base count only against the ceiling.
  • Each budget refills continuously. The account-group budget refills at one request each 6 seconds. It is not a fixed one-minute window that resets.
  • A request over either rate limit fails with HTTP 429. The request did nothing. The error message says which budget you reached and how long to wait. Wait, then send the same request again. Build your synchronization loop and your offboarding loop to expect this response. A loop that pushes or removes many sources on one account will reach the limit.
  • The character limits count Unicode characters, not bytes. Text in all languages gets the full budget.
  • A request over a character limit fails with HTTP 400. The response says which field is too long.
  • If your reference material is longer than the text limit, upload it as a file. A file has a size limit (50 MB), not a character limit.

Putting it all together

The full integration is one loop, plus an offboarding path. All the steps above are in this picture:

For file sources, the three-step upload procedure comes before each "Upsert Knowledge" box: request an upload URL, PUT the bytes, then upsert with the uploadHandle. If a creation is successful but the storage of the returned id fails, do the recovery in Step 8 before you push again.


Quick reference

TaskEndpointScope
List businesses (account groups)GET /platform/businessLocationsbusiness
List AI Employees on an accountPOST /grpc/v1/assistants/listai-assistant
Create or update knowledgePOST /grpc/v1/knowledge/upsertknowledge
Request a file upload URLPOST /grpc/v1/knowledge/file-uploadknowledge
Check processing statusPOST /grpc/v1/knowledge/statusknowledge
List knowledge sourcesPOST /grpc/v1/knowledge/listknowledge
Unlink or delete knowledgePOST /grpc/v1/knowledge/removeknowledge

Each gRPC-gateway endpoint is POST with a JSON body. The base is https://prod.apigateway.co/grpc. Each request contains the Authorization: Bearer <token> header. The full field-by-field references are in the AI Employees and AI Knowledge API specifications.