Skip to main content
Suri (formerly ChatbotMaker) is a Brazilian WhatsApp chatbot, CRM, and conversational commerce platform. This connector uses Suri’s REST API to extract contacts, message templates, campaigns, conversational flows, human-attendance history, and Suri Shop catalog/order data.
Suri is multi-tenant: each customer chatbot has its own API root and access token, both found in the chatbot’s Portal Settings.

Configuring Suri as a Source

In the Sources tab, click on the “Add source” button located on the top right of your screen. Then, select the Suri option from the list of connectors. Click Next and you’ll be prompted to add your access.

1. Add account access

Authentication uses a static Bearer token, unique per chatbot.
1

Open your chatbot's Portal Settings

In the Suri Portal, go to your chatbot’s settings to find its API root URL (formatted like https://xxx.azurewebsites.net/api) and API token.
2

Paste the API URL and token into Nekt

Fill in the Chatbot API URL and API Token fields with the values from the previous step.
The API Token grants full access to this chatbot’s data (contacts, messages, orders). Keep it secret — never share it or commit it to public code.
The following configurations are available:
  • Chatbot API URL: (Required) The chatbot’s API root, e.g. https://xxx.azurewebsites.net/api.
  • API Token: (Required) The static Bearer token from Portal Settings described above.
  • Start Date: (Optional) Lower bound for the shop_orders and attendances streams. If omitted, defaults to 30 days before the current date.
Once you’re done, click Next.

2. Select streams

Choose which data streams you want to sync. For faster extractions, select only the streams that are relevant to your analysis. You can select entire groups of streams or pick specific ones.
Tip: The stream can be found more easily by typing its name.
Select the streams and click Next.

3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.
  • Layer: choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
  • Folder: a folder can be created inside the selected layer to group all tables being created from this new data source.
  • Table name: we suggest a name, but feel free to customize it. You have the option to add a prefix to all tables at once and make this process faster!
  • Sync Type: you can choose between INCREMENTAL and FULL_TABLE.
    • Incremental: every time the extraction happens, we’ll get only the new data - which is good if, for example, you want to keep every record ever fetched.
    • Full table: every time the extraction happens, we’ll get the current state of the data - which is good if, for example, you don’t want to have deleted data in your catalog.
Once you are done configuring, click Next.

4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters. To define your Trigger, consider how often you want data to be extracted from this source. This decision usually depends on how frequently you need the new table data updated (every day, once a week, or only at specific times). Optionally, you can define some additional settings:
  • Configure Delta Log Retention and determine for how long we should store old states of this table as it gets updated. Read more about this resource here.
  • Determine when to execute an Additional Full Sync. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while.
Once you are ready, click Next to finalize the setup.

5. Check your new source

You can view your new source on the Sources page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.
For you to be able to see it on your Catalog, you need at least one successful source run.

Streams and Fields

Below you’ll find all available data streams from Suri and their corresponding fields.
Departments the chatbot can route contacts to, from /departments. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
NameStringDepartment name
Human attendants (agents) registered on the chatbot, from /attendants. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
nameStringAttendant name
emailStringAttendant email
Communication channels connected to the chatbot (WhatsApp, Webchat, etc.), from /channels. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
nameStringChannel name
providerIntegerProvider code
typeIntegerChannel type code
Reasons attendants can select when closing an attendance, from /attendances/reasons. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
nameStringReason label
WhatsApp/message templates registered on the chatbot, from /templates. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
chatbotIdStringChatbot the template belongs to
channelIdStringChannel the template is registered on
channelNameStringChannel display name
messageIdStringSubmission id at the provider (e.g. Meta)
titleStringTemplate title/name
bodyStringTemplate body text, with {{n}} placeholders
statusIntegerApproval status code
rejectedReasonStringRejection reason, if any
isWhatsappTemplateBooleanWhether it’s a WhatsApp-approved template
parametersIntegerNumber of {{n}} placeholders in the body
Bulk message campaigns sent from the chatbot, from /campaigns. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
chatbotIdStringChatbot the campaign belongs to
nameStringCampaign name
channelIdStringChannel the campaign sends through
whenDatetimeScheduled send date/time
statusIntegerCampaign status code
totalContacts, totalSent, totalDelivered, totalRead, totalErrors, totalAnswered, totalExpiredIntegerCampaign delivery counters
actionsArrayActions performed (e.g. which templates were sent)
dateCreate, dateStart, dateCancelDatetimeLifecycle timestamps
responseObjectHow replies to the campaign are routed
processingErrors, buttonsResponseString (raw JSON)Undocumented schema in the API reference
Conversational flows defined in the chatbot’s Portal flow builder, from /flows. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
chatbotIdStringChatbot the flow belongs to
nameStringFlow name
fixedBooleanWhether this is a built-in flow
versionIntegerFlow version number
trigger, actions, followUp, assistantBehaviorString (raw JSON)Trigger config and the flow’s action tree — actions is polymorphic (discriminated by a C# $type), so it’s kept as raw JSON rather than partially modeled
Chatbot contacts, listed via POST /contacts/list (the non-deprecated search endpoint). Full-table sync, paginated via continuationToken.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
nameStringContact display name
phoneStringPhone number (DDI+DDD+number)
emailStringContact email
dateCreateDatetimeWhen the contact was created
lastActivityDatetimeWhen the contact last interacted
tagsArray of StringTag identifiers currently applied
userTagsArray of ObjectTags with the date each was added
agent_status, agent_departmentId, agent_platformUserId, agent_unreadMessagesFlattened from the agent object: current attendance queue state
session_id, session_type, session_start, session_endFlattened from the session object: current messaging session
currentDialog, variablesString (raw JSON)Current flow position and free-form per-account custom fields — no fixed schema
POST /contacts/list has no date filter, only sort order (orderBy/orderType) — so there’s no way to ask the API for “only contacts changed since X”. This stream does a full sync every run.
Human attendance history, from POST /attendances. Incremental sync on startDate.Key Fields:
FieldTypeDescription
protocolStringUnique protocol number (primary key)
statusIntegerAttendance status code
startDate, endDate, requestDateDatetimeAttendance lifecycle timestamps (replication key: startDate)
attendantId, attendantNameStringAttendant who handled the attendance
departmentId, departmentNameStringDepartment the attendance was routed to
waitingTime, attendanceTime, avgResponseTimeNumberTiming metrics
reasonId, reasonStringAttendance reason selected when closing
user_id, user_name, user_email, user_phoneFlattened contact info for this attendance
orderString (raw JSON)Order tied to this attendance, if any — undocumented schema
POST /attendances requires an explicit startDate/endDate window (format yyyy-MM-dd) on every call. The API reference doesn’t document pagination for it, so each sync issues one request covering [bookmark or start_date or 30 days ago, today].
Product categories in the Suri Shop catalog, from /shop/categories. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
nameStringCategory name
descriptionStringCategory description
childrenString (raw JSON)Recursively nested subcategories
Physical/logistic stores in the Suri Shop catalog, from /shop/stores. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
nameStringStore name
fullAddressObjectStructured store address (state, city, street, zip code, etc.)
address, serviceTaxString (raw JSON)Observed as null in every sample response; undocumented schema
Curated product collections in the Suri Shop catalog, from /shop/collections. Full-table sync.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
providerIdStringIdentifier at the source provider
nameStringCollection name
shopIdStringShop the collection belongs to
productsArray of StringProvider IDs of the products in the collection
Products in the Suri Shop catalog, from POST /shop/products/list. Full-table sync, paginated via a pageToken cursor.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
skuStringBase SKU
categoryIdStringCategory the product belongs to
name, descriptionStringProduct name and description
price, promotionalPriceNumberPricing
isActiveBooleanWhether the product is active/visible
imagesArray of ObjectProduct images
attributesArray of ObjectVariant-defining attributes (e.g. color, size) and their values
dimensionsString (raw JSON)Product variants (SKU, per-attribute value, price, per-store stock) — kept as raw JSON since the attribute names and store ids inside it vary per product
Orders placed through the Suri Shop, from POST /shop/orders. Incremental sync on createdDate, paginated by page number.Key Fields:
FieldTypeDescription
idStringUnique identifier (primary key)
statusIntegerOrder status code (0 Creating, 1 Received, 2 Paid, 3 Cancelled, 4 Error)
createdDateDatetimeWhen the order was created (replication key)
receivedDate, finalizedDate, canceledDateDatetimeOrder lifecycle timestamps
itemsAmount, feeAmount, discountAmount, totalAmountNumberOrder totals
hasAssistance, isRebuy, isExternalOrder, isRecoveredOrderBooleanOrder flags
satisfactionSurveyObjectPost-order satisfaction survey response
seller, customer, logistic, payment, coupon, items, platformUser, errorMessages, origin, referralString (raw JSON)Observed as null/empty in every sample response, with no field-level docs — kept as raw JSON pending real order data
CreatedDate bounds the window server-side (undocumented default: last 30 days) and is used as both the replication key and the incremental filter — this only catches new orders, not status changes to orders created before the current bookmark window.

Implementation Notes

Sync mode

shop_orders and attendances sync incrementally. All other streams are full-table syncs.

Pagination

Suri’s simple GET list endpoints (departments, attendants, channels, templates, campaigns, flows, attendance reasons, shop categories/stores/collections) return their full result set in one response — every example in the API reference does, and no page/limit params are documented for them. The POST-based list/search endpoints paginate differently from each other:
  • contacts: cursor via continuationToken, echoed back in the request body.
  • shop_products: cursor via pageToken + a hasMore flag, both under data.
  • shop_orders: page number (Page/PerPage in the request body) + a hasMore flag under data.

API limitations / undocumented behavior

This V1 was built entirely from the public API reference — Nekt does not yet have access to the requesting customer’s Suri account to validate against real data. Known gaps:
  • contacts has no server-side date filter, so it’s a full sync every run (see the Contacts note above).
  • Several nested fields have no documented schema and were always null/empty in every sample response: shop_orders.seller/customer/logistic/payment/items/platformUser/errorMessages/origin/referral, flows.actions/trigger, and shop_products.dimensions’s inner variant/stock shape. These are kept as raw JSON strings.
  • The “get by id” endpoints (contact, template, campaign, category, product, order, collection, flow, attendance reason by id) and GET /contacts/:user_id/messages exist in the API but aren’t included in V1 — they need an id from a parent stream and largely duplicate data already present in the corresponding list endpoint.
  • Write/action endpoints (import contact, send message, create/update/delete category/product/collection/order actions, webhook registration) are out of scope for an extractor.

Skills for agents

Download Suri skills file

Suri connector documentation as plain markdown, for use in AI agent contexts.