Heyy
MESSAGING · MESSAGING
Workspace teams, users, conversations, and files in the account they connected.
Acts as the person, not as itself
Each user connects their own account. Every call carries both identities — the agent and the person it is acting for — so the agent can never reach past what that individual can already do.
Credentials never touch the agent
Tokens live in the vault and attach server-side at call time. The agent holds a session, not a secret, and revoking access does not mean rotating a key.
Every call on the record
Who asked, which agent acted, which action ran, and the verdict that let it through — one audit trail across every integration, not one per vendor.
What an agent can do
Each action is granted on its own. An agent allowed to read is not thereby allowed to write, and the scope beside each row is what the acting user must have connected for it to run at all.
heyy_delete_api_webhooks_by_webhookidWRITEDelete API webhook via DELETE /api_webhooks/{webhookId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_attributes_by_attributeidWRITEDelete attribute via DELETE /attributes/{attributeId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_campaigns_by_campaignidWRITEDelete campaign via DELETE /campaigns/{campaignId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_campaigns_by_campaignid_recipientsWRITERemove recipients via DELETE /campaigns/{campaignId}/recipients. Names the recipients to remove in a JSON BODY -- the campaign is in the path, the recipients are not -- so this is one of only two DELETEs on this surface that sends a body. A caller that sends none removes nothing while the call still succeeds. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_chats_by_chatidWRITEDelete chat via DELETE /chats/{chatId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_contacts_by_contactidWRITEDelete contact via DELETE /contacts/{contactId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_contacts_by_contactid_labelsWRITERemove labels from contact via DELETE /contacts/{contactId}/labels. Names the labels to remove in a JSON BODY, not in the path, so this is the second of only two DELETEs on this surface that sends a body. It detaches labels from the contact and does not delete the labels themselves -- Delete label is what destroys a label for the whole workspace. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_labels_by_labelidWRITEDelete label via DELETE /labels/{labelId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_message_templates_by_messagetemplateidWRITEDelete message template via DELETE /message_templates/{messageTemplateId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_delete_teams_by_teamidWRITEDelete team via DELETE /teams/{teamId}. DESTRUCTIVE and not reversible through this API: Heyy's v3 contract publishes no undelete and no recycle bin, so the only recovery is re-creating the resource.
heyy_get_attributes_by_attributeidREADGet attribute via GET /attributes/{attributeId}.
heyy_get_automations_by_automationidREADGet automation via GET /automations/{automationId}.
heyy_get_campaigns_by_campaignidREADGet campaign via GET /campaigns/{campaignId}.
heyy_get_channels_by_channelidREADGet channel via GET /channels/{channelId}.
heyy_get_chats_by_chatidREADGet chat via GET /chats/{chatId}.
heyy_get_contacts_by_contactidREADGet contact via GET /contacts/{contactId}.
heyy_get_files_by_fileidREADGet file via GET /files/{fileId}. Reads a file record that already exists in the workspace. UPLOADING is not part of this integration: Heyy's `POST /files` is a multipart binary upload and is withheld, so a `fileId` referenced by the message, template and campaign tools has to be created in the Heyy app or by calling that endpoint outside Agentic Fabriq.
heyy_get_files_by_fileid_public_urlREADGet public file URL via GET /files/{fileId}/public_url. Returns a stable public URL for an uploaded file, creating one if it does not exist yet. Use this URL when referencing the file by URL (for example, in automation template media overrides). The URL does not expire.
heyy_get_journeys_by_journeyidREADGet journey via GET /journeys/{journeyId}.
heyy_get_labels_by_labelidREADGet label via GET /labels/{labelId}.
heyy_get_message_templates_by_messagetemplateidREADGet message template via GET /message_templates/{messageTemplateId}.
heyy_get_teams_by_teamidREADGet team via GET /teams/{teamId}.
heyy_get_usersREADGet users via GET /users. Returns the workspace's members. This is a plain GET rather than a `POST /users/search`, so it takes no filter, sort or page arguments at all -- the two listings that behave this way are users and workspace.
heyy_get_users_by_useridREADGet user via GET /users/{userId}.
heyy_get_workspaceREADGet workspace via GET /workspace. Returns the workspace associated with the API key. Takes no arguments and is the cheapest read on the surface, which is why it is also what Agentic Fabriq probes a pasted API key with: the key identifies its own workspace, so there is nothing to select.
heyy_post_api_webhooksWRITECreate API webhook via POST /api_webhooks. Registers a URL Heyy will POST workspace events to. The delivery target is the customer's own endpoint, so anything this webhook is pointed at receives Heyy's event payloads -- including message content -- until the webhook is deleted.
heyy_post_api_webhooks_searchWRITESearch API webhooks via POST /api_webhooks/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_attributesWRITECreate attribute via POST /attributes.
heyy_post_attributes_searchWRITESearch attributes via POST /attributes/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_automations_by_automationid_pauseWRITEPause automation via POST /automations/{automationId}/pause.
heyy_post_automations_by_automationid_triggerWRITETrigger automation via POST /automations/{automationId}/trigger. Starts an automation for a contact, with input parameters. Heyy names this as the SAFER way to reach a contact than sending directly: an automation can carry a subscription condition, while the message tools check nothing. What the automation then does -- including sending -- is configured in Heyy, not here, so the effect of this call is whatever that automation is built to do.
heyy_post_automations_by_automationid_unpauseWRITEUnpause automation via POST /automations/{automationId}/unpause.
heyy_post_automations_searchWRITESearch automations via POST /automations/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_campaignsWRITECreate campaign via POST /campaigns.
heyy_post_campaigns_by_campaignid_recipientsWRITEAdd recipients via POST /campaigns/{campaignId}/recipients.
heyy_post_campaigns_by_campaignid_startWRITEStart campaign via POST /campaigns/{campaignId}/start. Starts the campaign SENDING. This is the point of no return for a broadcast: every recipient currently on the campaign is messaged, the sends are billed as message credits, and nothing in this API unsends them. Read the campaign and its recipients back before calling it.
heyy_post_campaigns_searchWRITESearch campaigns via POST /campaigns/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_channels_searchWRITESearch channels via POST /channels/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_chats_by_chatid_assign_teamWRITEAssign chat to team via POST /chats/{chatId}/assign_team.
heyy_post_chats_by_chatid_assign_userWRITEAssign chat to user via POST /chats/{chatId}/assign_user.
heyy_post_chats_by_chatid_mark_as_not_sensitiveWRITEMark chat as not sensitive via POST /chats/{chatId}/mark_as_not_sensitive. Clears the sensitive flag, which WIDENS who on the team can read the conversation. It is the reverse of Mark chat as sensitive and is not classified destructive, but it does expose a chat that somebody deliberately restricted.
heyy_post_chats_by_chatid_mark_as_readWRITEMark chat as read via POST /chats/{chatId}/mark_as_read.
heyy_post_chats_by_chatid_mark_as_sensitiveWRITEMark chat as sensitive via POST /chats/{chatId}/mark_as_sensitive. Flags the conversation as containing sensitive information, which is a visibility control inside Heyy rather than a note: it restricts who on the team can read the chat.
heyy_post_chats_by_chatid_mark_as_unreadWRITEMark chat as unread via POST /chats/{chatId}/mark_as_unread.
heyy_post_chats_by_chatid_statusWRITEChange chat status via POST /chats/{chatId}/status.
heyy_post_chats_searchWRITESearch chats via POST /chats/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_contactsWRITECreate contact via POST /contacts.
heyy_post_contacts_bulkWRITEBulk upsert contacts via POST /contacts/bulk. Upserts many contacts in one call, with the same match-by-identifier behaviour as Upsert contact. A partial failure is reported by Heyy in the response rather than raised here, so read the result instead of treating a 200 as "all rows landed".
heyy_post_contacts_by_contactid_labelsWRITEAdd labels to contact via POST /contacts/{contactId}/labels. Attaches existing labels to the contact. It does not create a label -- Create label does that -- and labels are what the campaign and search tools filter audiences on, so adding one can change who a scheduled campaign reaches.
heyy_post_contacts_by_contactid_subscribeWRITESubscribe contact via POST /contacts/{contactId}/subscribe.
heyy_post_contacts_by_contactid_unsubscribeWRITEUnsubscribe contact via POST /contacts/{contactId}/unsubscribe. Records that the contact has opted out. It does not by itself stop the message tools: Send message and Send template message deliver to an unsubscribed contact, because Heyy makes the consent check the caller's responsibility.
heyy_post_contacts_searchWRITESearch contacts via POST /contacts/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_contacts_upsertWRITEUpsert contact via POST /contacts/upsert. Creates the contact or MATCHES an existing one by identifier (phone number or email) and updates it. This is the tool to use when the identifier may already exist -- Create contact fails on a duplicate, and Update contact cannot change a phone number or an email at all.
heyy_post_journeys_by_journeyid_subscribeWRITESubscribe contacts to journey via POST /journeys/{journeyId}/subscribe. Adds contacts to a journey, which may begin messaging them immediately depending on how the journey is built in Heyy.
heyy_post_journeys_by_journeyid_unsubscribeWRITEUnsubscribe contacts from journey via POST /journeys/{journeyId}/unsubscribe.
heyy_post_journeys_searchWRITESearch journeys via POST /journeys/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_labelsWRITECreate label via POST /labels.
heyy_post_labels_searchWRITESearch labels via POST /labels/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_message_templatesWRITECreate message template via POST /message_templates.
heyy_post_message_templates_searchWRITESearch message templates via POST /message_templates/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_post_messages_sendWRITESend message via POST /messages/send. Sends a free-form message on a channel the workspace has already connected. TWO THINGS THIS SPENDS THAT NO OTHER TOOL DOES. It contacts a real person, and on WhatsApp it consumes message credits, which Heyy bills on top of the plan -- there is no dry run. And consent is the CALLER's job: Heyy's own reference states that for a MARKETING message "you are responsible for confirming the contact is subscribed before you call it. The message will be sent even if the contact is unsubscribed." Check `isSubscribed` with Get contact first, or use Trigger automation, which Heyy names as the path where a subscription condition can gate the send. Free-form replies also stop working once the channel's conversation window has closed; that is when a template message is the only form that will deliver.
heyy_post_messages_send_templateWRITESend template message via POST /messages/send_template. Sends a pre-approved template message, which is what reaches a contact AFTER the channel's free-form conversation window has closed. The same consent rule applies verbatim: for a MARKETING message "you are responsible for confirming the contact is subscribed before you call it. The message will be sent even if the contact is unsubscribed." WhatsApp templates are approved by Meta rather than by Heyy, so a template that is not approved for the channel fails at Heyy's end rather than here, and the same message credits are spent.
heyy_post_teamsWRITECreate team via POST /teams.
heyy_post_teams_searchWRITESearch teams via POST /teams/search. This is a LIST endpoint even though it is a POST: filtering (`query`), ordering (`sortBy`), free-text matching (`search`) and paging (`pagination`, zero-based `page` with a `limit` of 1-100, default 10) all travel in the request body, and the response wraps the rows in `data` with a `pagination.total`. Send an empty body to get the first page unfiltered.
heyy_put_api_webhooks_by_webhookidWRITEUpdate API webhook via PUT /api_webhooks/{webhookId}.
heyy_put_attributes_by_attributeidWRITEUpdate attribute via PUT /attributes/{attributeId}.
heyy_put_campaigns_by_campaignidWRITEUpdate campaign via PUT /campaigns/{campaignId}.
heyy_put_contacts_by_contactidWRITEUpdate contact via PUT /contacts/{contactId}. Updates contact profile fields (first name, last name, and custom attributes). Phone number and email cannot be changed here — use upsert to create or match by identifier.
heyy_put_labels_by_labelidWRITEUpdate label via PUT /labels/{labelId}.
heyy_put_message_templates_by_messagetemplateidWRITEUpdate message template via PUT /message_templates/{messageTemplateId}.
heyy_put_teams_by_teamidWRITEUpdate team via PUT /teams/{teamId}.
Often connected alongside
Put Heyy behind one governed endpoint.
Same permissions, same audit trail, whatever else you connect next.