Build with the K2 platform
Scoped API keys, authentication, permissions, request fields, rate limits, cURL examples, and responses for K2Mailer email marketing, PushWave web push, and AI Chat Assistant.
Reference reviewed against the current K2Mailer API routes and API key scope model on August 13, 2026.
K2Mailer authentication
Create scoped API keys for each integration
K2Mailer API keys are tenant-scoped credentials. Create a separate key for production, Zapier, reporting, or another integration, then grant only the scopes that integration needs.
Quick start
- 1Open Settings → API, enable API access, and select Create API Key.
- 2Name the key, choose the minimum required scopes, choose an expiry, and create it. The full secret is shown once.
- 3Send the secret in the
Authorizationheader as a Bearer credential. Keep it in server-side secret storage, not browser JavaScript or a public repository.
curl --request GET --url 'https://app.k2mailer.com/api/v1/user' --header 'Authorization: Bearer YOUR_API_KEY' --header 'Accept: application/json'Key lifecycle
- • New secrets are stored as hashes and cannot be displayed again.
- • Each key can have its own expiry and can be revoked independently.
- • Last-used time and IP are recorded after successful authentication.
- • Disabling tenant API access immediately blocks every key for that tenant.
Legacy keys
Existing pre-upgrade API tokens are migrated as Legacy API Key credentials with full-access scope for compatibility. Create a scoped replacement for each integration, switch the integration, then revoke the legacy key.
Scopes
Least-privilege permissions
Every K2Mailer REST endpoint below shows its required scope.
account.readAccountRead basic account information for the tenant.
clients.writeClientsCreate client accounts through approved provisioning workflows.
groups.readGroupsList and view groups.
groups.writeGroupsCreate, update, and delete groups.
lists.readListsList and view contact lists.
lists.writeListsCreate, update, and delete contact lists.
custom_fields.readCustom fieldsList and view contact custom fields.
custom_fields.writeCustom fieldsCreate, update, and delete contact custom fields.
contacts.readContactsList and view contacts.
contacts.writeContactsCreate, update, remove, and delete contacts.
campaigns.readCampaignsList and view saved broadcasts/campaigns.
campaigns.writeCampaignsCreate, update, and delete saved broadcasts/campaigns.
401
Invalid, expired, or revoked key. The API intentionally returns the same generic unauthenticated response for each case.
403
A valid key lacks the endpoint scope, or tenant API access has been disabled.
422
Request validation failed. Review the response errors and required request fields.
429
The REST API is limited to 60 requests per minute by the application API middleware.
Collection pagination
Collection endpoints use start_from as a zero-based offset and return up to 500 records. They do not accept a limit parameter.
Response format
Most resources return a status and response JSON envelope. GET /user returns the user object directly. Some business-rule errors can still use HTTP 200 with JSON status: Error, so inspect both layers.
Response behavior
Read both HTTP and JSON status
K2Mailer business-rule errors can return HTTP 200 with a JSON status of Error. Authentication, authorization, validation, and rate-limit failures use 401, 403, 422, and 429.
PushWave key safety
Public and Secret keys are different
A pk_ Public Key is safe for browser integration endpoints. An sk_ Secret Key is private and required for every broadcast operation. Never expose the Secret Key in WordPress front-end JavaScript or a public page.
AI widget origin
Allow the production domain
Public chat session, lead, message, stream, rating, and escalation calls validate the Origin header against the bot’s allowed domains. Add every production domain before launch.
56 operations
Email marketing
K2Mailer REST API
Manage account data, audiences, contacts, custom fields, and saved broadcast content.
- Authentication
- Bearer API key
- Settings → API. Enable API access, create a key, choose its scopes, and copy the secret when it is shown.
- Base URL
- https://app.k2mailer.com/api/v1
- 60 requests per minute
Account
2 operationsGET/userGet the authenticated user
Return the user and workspace identity associated with the authenticated API key.
/userGet the authenticated user
Return the user and workspace identity associated with the authenticated API key.
Authentication
K2Mailer Bearer API key
Required scope
account.read
Rate limit
60/min
Success
HTTP 200
Important
- Unlike the other K2Mailer REST resources, this endpoint returns the user object without a status/response envelope.
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/user' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"id": 7,
"name": "API User",
"email": "api@example.com",
"language": "en",
"time_zone": "UTC",
"active": true,
"is_client": false,
"primary_product": "k2mailer"
}POST/client/addProvision a client account
Create an isolated client workspace linked to the authenticated parent account.
/client/addProvision a client account
Create an isolated client workspace linked to the authenticated parent account.
Authentication
K2Mailer Bearer API key
Required scope
clients.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
nameRequired | body | string | Client display name. |
emailRequired | body | Unique login email. | |
passwordRequired | body | string | Password with at least 8 characters. |
list_id | body | integer | Optional list owned by the authenticating account. |
product | body | string | Optional initial product assignment. |
custom_fields | body | object | Optional custom field values. |
Important
- This endpoint is for approved client-provisioning workflows, not ordinary contact creation.
- The authenticated account must have permission to create clients.
curl --request POST \
--url 'https://app.k2mailer.com/api/v1/client/add' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "Acme Marketing",
"email": "owner@acme.example",
"password": "a-strong-password",
"product": "K2Mailer"
}'{
"status": "Success",
"response": {
"email": "owner@acme.example",
"login_token": "one-time-login-token"
}
}Groups
5 operationsGET/groupsList Groups
Return Groups belonging to the authenticated account.
/groupsList Groups
Return Groups belonging to the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
groups.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
type_id | query | integer | Filter by group type. |
start_from | query | integer | Zero-based result offset. Defaults to 0. |
Important
- This endpoint returns up to 500 records after start_from. It does not accept a limit parameter.
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/groups?type_id=1&start_from=0' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": [
{
"id": 42,
"name": "Example group"
}
]
}GET/groups/{id}Get a group
Return one tenant-owned group.
/groups/{id}Get a group
Return one tenant-owned group.
Authentication
K2Mailer Bearer API key
Required scope
groups.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned group ID. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/groups/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example group"
}
}POST/groupsCreate a group
Create a new group in the authenticated account.
/groupsCreate a group
Create a new group in the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
groups.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
nameRequired | body | string | Group name. |
type_idRequired | body | integer | Group type: 1 lists, 2 broadcasts, or 3 sending servers. |
curl --request POST \
--url 'https://app.k2mailer.com/api/v1/groups' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "Newsletter audiences",
"type_id": 1
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example group"
}
}PATCH/groups/{id}Update a group
Update fields on an existing tenant-owned group.
/groups/{id}Update a group
Update fields on an existing tenant-owned group.
Authentication
K2Mailer Bearer API key
Required scope
groups.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned group ID. |
name | body | string | Updated group name. |
curl --request PATCH \
--url 'https://app.k2mailer.com/api/v1/groups/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "Updated newsletter audiences"
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example group"
}
}DELETE/groups/{id}Delete a group
Delete a tenant-owned group.
/groups/{id}Delete a group
Delete a tenant-owned group.
Authentication
K2Mailer Bearer API key
Required scope
groups.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned group ID. |
curl --request DELETE \
--url 'https://app.k2mailer.com/api/v1/groups/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example group"
}
}Lists
5 operationsGET/listsList Lists
Return Lists belonging to the authenticated account.
/listsList Lists
Return Lists belonging to the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
lists.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
group_id | query | integer | Filter by tenant-owned list group. |
start_from | query | integer | Zero-based result offset. Defaults to 0. |
Important
- This endpoint returns up to 500 records after start_from. It does not accept a limit parameter.
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/lists?group_id=12&start_from=0' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": [
{
"id": 42,
"name": "Example list"
}
]
}GET/lists/{id}Get a list
Return one tenant-owned list.
/lists/{id}Get a list
Return one tenant-owned list.
Authentication
K2Mailer Bearer API key
Required scope
lists.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned list ID. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/lists/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example list"
}
}POST/listsCreate a list
Create a new list in the authenticated account.
/listsCreate a list
Create a new list in the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
lists.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
nameRequired | body | string | List name. |
group_idRequired | body | integer | Tenant-owned list group ID. |
sending_server_idRequired | body | integer | Tenant-owned sending server ID. |
custom_field_id | body | integer[] | Custom fields to associate with the list. |
double_optin | body | Yes | No | Whether confirmation is required. |
welcome_email | body | Yes | No | Whether the list sends a welcome email. |
unsub_email | body | Yes | No | Whether to send the list unsubscribe email. |
notification | body | Enabled | Disabled | Enable list-owner subscription notifications. |
notification_email | body | Destination for enabled list notifications. | |
notification_criteria | body | string | Notification rule stored with the list. |
Important
- Group, sending server, and custom field IDs must all belong to the authenticated account.
- PATCH does not change the custom fields associated with a list.
curl --request POST \
--url 'https://app.k2mailer.com/api/v1/lists' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "Product newsletter",
"group_id": 12,
"sending_server_id": 4,
"custom_field_id": [
8,
9
],
"double_optin": "Yes",
"welcome_email": "Yes"
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example list"
}
}PATCH/lists/{id}Update a list
Update fields on an existing tenant-owned list.
/lists/{id}Update a list
Update fields on an existing tenant-owned list.
Authentication
K2Mailer Bearer API key
Required scope
lists.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned list ID. |
name | body | string | Updated list name. |
group_id | body | integer | Updated tenant-owned list group ID. |
sending_server_id | body | integer | Updated tenant-owned sending server ID. |
double_optin | body | Yes | No | Whether confirmation is required. |
welcome_email | body | Yes | No | Whether the list sends a welcome email. |
unsub_email | body | Yes | No | Whether to send the list unsubscribe email. |
notification | body | Enabled | Disabled | Enable list-owner subscription notifications. |
notification_email | body | Destination for enabled list notifications. | |
notification_criteria | body | string | Notification rule stored with the list. |
Important
- Group, sending server, and custom field IDs must all belong to the authenticated account.
- PATCH does not change the custom fields associated with a list.
curl --request PATCH \
--url 'https://app.k2mailer.com/api/v1/lists/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "Updated product newsletter",
"group_id": 12,
"sending_server_id": 4,
"double_optin": "Yes"
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example list"
}
}DELETE/lists/{id}Delete a list
Delete a tenant-owned list.
/lists/{id}Delete a list
Delete a tenant-owned list.
Authentication
K2Mailer Bearer API key
Required scope
lists.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned list ID. |
curl --request DELETE \
--url 'https://app.k2mailer.com/api/v1/lists/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example list"
}
}Custom fields
5 operationsGET/custom-fieldsList Custom fields
Return Custom fields belonging to the authenticated account.
/custom-fieldsList Custom fields
Return Custom fields belonging to the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
custom_fields.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
start_from | query | integer | Zero-based result offset. Defaults to 0. |
Important
- This endpoint returns up to 500 records after start_from. It does not accept a limit parameter.
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/custom-fields?start_from=0' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": [
{
"id": 42,
"name": "Example custom field"
}
]
}GET/custom-fields/{id}Get a custom field
Return one tenant-owned custom field.
/custom-fields/{id}Get a custom field
Return one tenant-owned custom field.
Authentication
K2Mailer Bearer API key
Required scope
custom_fields.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned custom field ID. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/custom-fields/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example custom field"
}
}POST/custom-fieldsCreate a custom field
Create a new custom field in the authenticated account.
/custom-fieldsCreate a custom field
Create a new custom field in the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
custom_fields.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
nameRequired | body | string | Field label. |
type | body | string | Field type. Defaults to text. |
value | body | string[] | Options for radio, checkbox, or dropdown fields. |
required | body | boolean | Whether contacts must provide the field. |
Important
- The options property is named value, singular.
- PATCH currently changes only the custom field name.
curl --request POST \
--url 'https://app.k2mailer.com/api/v1/custom-fields' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "Company size",
"type": "dropdown",
"value": [
"1-10",
"11-50",
"51+"
],
"required": false
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example custom field"
}
}PATCH/custom-fields/{id}Update a custom field
Update fields on an existing tenant-owned custom field.
/custom-fields/{id}Update a custom field
Update fields on an existing tenant-owned custom field.
Authentication
K2Mailer Bearer API key
Required scope
custom_fields.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned custom field ID. |
name | body | string | Updated field name. |
Important
- The options property is named value, singular.
- PATCH currently changes only the custom field name.
curl --request PATCH \
--url 'https://app.k2mailer.com/api/v1/custom-fields/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "Updated company size"
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example custom field"
}
}DELETE/custom-fields/{id}Delete a custom field
Delete a tenant-owned custom field.
/custom-fields/{id}Delete a custom field
Delete a tenant-owned custom field.
Authentication
K2Mailer Bearer API key
Required scope
custom_fields.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned custom field ID. |
curl --request DELETE \
--url 'https://app.k2mailer.com/api/v1/custom-fields/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example custom field"
}
}Contacts
6 operationsGET/contactsList contacts
Return contacts belonging to the authenticated account.
/contactsList contacts
Return contacts belonging to the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
contacts.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
list_id | query | integer | Filter by tenant-owned list. |
start_from | query | integer | Zero-based result offset. Defaults to 0. |
Important
- This endpoint returns up to 500 records after start_from. It does not accept a limit parameter.
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/contacts?list_id=15&start_from=0' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": [
{
"id": 81,
"email": "reader@example.com",
"list_id": 15
}
]
}GET/contacts/{id}Get a contact
Return one tenant-owned contact and its saved fields.
/contacts/{id}Get a contact
Return one tenant-owned contact and its saved fields.
Authentication
K2Mailer Bearer API key
Required scope
contacts.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned contact ID. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/contacts/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 81,
"email": "reader@example.com",
"list_id": 15,
"active": "Yes"
}
}POST/contactsCreate a contact
Add a contact to a tenant-owned list.
/contactsCreate a contact
Add a contact to a tenant-owned list.
Authentication
K2Mailer Bearer API key
Required scope
contacts.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
emailRequired | body | Contact email address. | |
list_idRequired | body | integer | Tenant-owned destination list. |
format | body | HTML | Text | Preferred email format. Defaults to HTML. |
active | body | Yes | No | Contact active state. Defaults to Yes. |
confirm | body | Yes | No | Whether to run the list confirmation or welcome-email flow. Defaults to Yes. |
unsubscribed | body | Yes | No | Unsubscribe state. Defaults to No. |
custom_fields | body | object | Values keyed by tenant-owned custom field ID. |
Important
- New contacts default to HTML format, active, confirmed, and not unsubscribed.
curl --request POST \
--url 'https://app.k2mailer.com/api/v1/contacts' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"email": "reader@example.com",
"list_id": 15,
"custom_fields": {
"8": "Acme",
"9": "11-50"
}
}'{
"status": "Success",
"response": {
"id": 81,
"email": "reader@example.com",
"list_id": 15
}
}POST/contacts/removeRemove a contact by email
Remove an email address from a specific tenant-owned list.
/contacts/removeRemove a contact by email
Remove an email address from a specific tenant-owned list.
Authentication
K2Mailer Bearer API key
Required scope
contacts.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
emailRequired | body | Contact email address. | |
list_idRequired | body | integer | Tenant-owned list ID. |
curl --request POST \
--url 'https://app.k2mailer.com/api/v1/contacts/remove' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"email": "reader@example.com",
"list_id": 15
}'{
"status": "Success",
"response": "Contact removed"
}PATCH/contacts/{id}Update a contact
Update the email address or replace custom field values for a contact.
/contacts/{id}Update a contact
Update the email address or replace custom field values for a contact.
Authentication
K2Mailer Bearer API key
Required scope
contacts.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned contact ID. |
email | body | Updated email address. | |
list_id | body | integer | Accepted for validation but the contact remains on its current list. |
format | body | HTML | Text | Updated email format. |
active | body | Yes | No | Updated active state. |
unsubscribed | body | Yes | No | Updated unsubscribe state. |
custom_fields | body | object | Replacement values keyed by custom field ID. |
Important
- A PATCH cannot move the contact to another list.
- When custom_fields is provided, it replaces the stored custom field values.
curl --request PATCH \
--url 'https://app.k2mailer.com/api/v1/contacts/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"email": "new-address@example.com",
"custom_fields": {
"8": "Updated company"
}
}'{
"status": "Success",
"response": {
"id": 81,
"email": "new-address@example.com"
}
}DELETE/contacts/{id}Delete a contact
Delete a tenant-owned contact by ID.
/contacts/{id}Delete a contact
Delete a tenant-owned contact by ID.
Authentication
K2Mailer Bearer API key
Required scope
contacts.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned contact ID. |
curl --request DELETE \
--url 'https://app.k2mailer.com/api/v1/contacts/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": "Contact deleted"
}Broadcasts
5 operationsGET/broadcastsList Broadcasts
Return Broadcasts belonging to the authenticated account.
/broadcastsList Broadcasts
Return Broadcasts belonging to the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
campaigns.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
group_id | query | integer | Filter by tenant-owned broadcast group. |
start_from | query | integer | Zero-based result offset. Defaults to 0. |
Important
- This endpoint returns up to 500 records after start_from. It does not accept a limit parameter.
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/broadcasts?group_id=12&start_from=0' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": [
{
"id": 42,
"name": "Example broadcast"
}
]
}GET/broadcasts/{id}Get a broadcast
Return one tenant-owned broadcast.
/broadcasts/{id}Get a broadcast
Return one tenant-owned broadcast.
Authentication
K2Mailer Bearer API key
Required scope
campaigns.read
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned broadcast ID. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/broadcasts/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example broadcast"
}
}POST/broadcastsCreate a broadcast
Create a new broadcast in the authenticated account.
/broadcastsCreate a broadcast
Create a new broadcast in the authenticated account.
Authentication
K2Mailer Bearer API key
Required scope
campaigns.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
nameRequired | body | string | Internal broadcast name. |
group_idRequired | body | integer | Tenant-owned broadcast group ID. |
email_subjectRequired | body | string | Email subject line. |
html | body | string | URL-encoded HTML content. |
text | body | string | URL-encoded plain-text content. |
Important
- This resource saves email content. It does not send or schedule a campaign.
curl --request POST \
--url 'https://app.k2mailer.com/api/v1/broadcasts' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "April update",
"group_id": 22,
"email_subject": "What is new this month",
"html": "%3Ch1%3EApril%20update%3C%2Fh1%3E",
"text": "April%20update"
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example broadcast"
}
}PATCH/broadcasts/{id}Update a broadcast
Update fields on an existing tenant-owned broadcast.
/broadcasts/{id}Update a broadcast
Update fields on an existing tenant-owned broadcast.
Authentication
K2Mailer Bearer API key
Required scope
campaigns.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned broadcast ID. |
name | body | string | Internal broadcast name. |
group_id | body | integer | Tenant-owned broadcast group ID. |
email_subject | body | string | Email subject line. |
html | body | string | URL-encoded HTML content. |
text | body | string | URL-encoded plain-text content. |
Important
- This resource saves email content. It does not send or schedule a campaign.
curl --request PATCH \
--url 'https://app.k2mailer.com/api/v1/broadcasts/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"name": "April update",
"group_id": 22,
"email_subject": "What is new this month",
"html": "%3Ch1%3EApril%20update%3C%2Fh1%3E",
"text": "April%20update"
}'{
"status": "Success",
"response": {
"id": 42,
"name": "Example broadcast"
}
}DELETE/broadcasts/{id}Delete a broadcast
Delete a tenant-owned broadcast.
/broadcasts/{id}Delete a broadcast
Delete a tenant-owned broadcast.
Authentication
K2Mailer Bearer API key
Required scope
campaigns.write
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
idRequired | path | integer | The tenant-owned broadcast ID. |
curl --request DELETE \
--url 'https://app.k2mailer.com/api/v1/broadcasts/42' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Accept: application/json'{
"status": "Success",
"response": {
"id": 42,
"name": "Example broadcast"
}
}Web push
PushWave API
Register browser subscriptions, record events, and manage push broadcasts.
- Authentication
- Public or Secret Key
- PushWave → Sites. Use the key required by each endpoint group.
- Base URL
- https://app.k2mailer.com
- 10–120 requests per minute, depending on the endpoint
Browser integration
2 operationsGET/api/pushwave/configGet site configuration
Return public widget, prompt, and site settings for the Public Key.
/api/pushwave/configGet site configuration
Return public widget, prompt, and site settings for the Public Key.
Authentication
PushWave Public Key
Rate limit
30/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
curl --request GET \
--url 'https://app.k2mailer.com/api/pushwave/config' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json'{
"soft_prompt_enabled": true,
"vapid_public_key": "BExampleVapidPublicKey",
"site_name": "Example site",
"site_icon": "https://app.k2mailer.com/storage/site-icon.png",
"data_notice_text": "We use notifications to send important updates.",
"privacy_policy_url": "https://example.com/privacy",
"unsubscribe_url": "https://app.k2mailer.com/pushwave/unsubscribed/11",
"resubscribe_url": "https://example.com/?pushwave_resubscribe=1"
}GET/api/pushwave/vapid-keyGet VAPID public key
Return the VAPID public key used by the browser Push API.
/api/pushwave/vapid-keyGet VAPID public key
Return the VAPID public key used by the browser Push API.
Authentication
PushWave Public Key
Rate limit
30/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
curl --request GET \
--url 'https://app.k2mailer.com/api/pushwave/vapid-key' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json'{
"vapid_public_key": "BExampleVapidPublicKey"
}Subscriptions
3 operationsPOST/api/pushwave/subscribeSubscribe a browser
Register a browser push subscription with the site.
/api/pushwave/subscribeSubscribe a browser
Register a browser push subscription with the site.
Authentication
PushWave Public Key
Rate limit
10/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
endpointRequired | body | URL | Push service endpoint, maximum 2,000 characters. |
p256dh_keyRequired | body | string | Browser subscription p256dh key. |
auth_keyRequired | body | string | Browser subscription auth secret. |
browser | body | string | Browser name, maximum 100 characters. |
browser_version | body | string | Browser version, maximum 50 characters. |
device_type | body | desktop | mobile | tablet | Detected device category. |
os | body | string | Operating system, maximum 100 characters. |
timezone | body | string | Browser timezone, maximum 100 characters. |
language | body | string | Browser language, maximum 20 characters. |
subscribed_page_url | body | string | Page on which subscription occurred, maximum 2,000 characters. |
user_agent | body | string | Browser user agent, maximum 512 characters. |
consent_method | body | soft_prompt | native_prompt | api | How consent was collected. |
consent_page_url | body | string | Page on which consent was granted, maximum 2,000 characters. |
confirm_resubscribe | body | boolean | Confirm a user-requested resubscribe after prior suppression. |
Important
- An endpoint registered to another site returns 409 endpoint_already_registered.
- A previously suppressed endpoint returns 409 subscriber_suppressed until the user confirms and the request is retried with confirm_resubscribe.
- A plan limit returns 429 subscriber_limit_reached.
curl --request POST \
--url 'https://app.k2mailer.com/api/pushwave/subscribe' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"endpoint": "https://push.example.net/subscription/abc",
"p256dh_key": "browser-p256dh-key",
"auth_key": "browser-auth-key",
"browser": "Chrome",
"browser_version": "126",
"device_type": "desktop",
"os": "Windows",
"timezone": "Asia/Karachi",
"language": "en",
"subscribed_page_url": "https://example.com/pricing",
"consent_method": "native_prompt"
}'{
"subscriber_id": 9021,
"status": "subscribed"
}POST/api/pushwave/unsubscribeUnsubscribe a browser
Mark the matching browser endpoint as unsubscribed for the site.
/api/pushwave/unsubscribeUnsubscribe a browser
Mark the matching browser endpoint as unsubscribed for the site.
Authentication
PushWave Public Key
Rate limit
20/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
endpointRequired | body | URL | The browser push service endpoint. |
curl --request POST \
--url 'https://app.k2mailer.com/api/pushwave/unsubscribe' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"endpoint": "https://push.example.net/subscription/abc"
}'{
"ok": true,
"affected": 1
}POST/api/pushwave/prompt-eventRecord a prompt event
Record an opt-in prompt impression or outcome.
/api/pushwave/prompt-eventRecord a prompt event
Record an opt-in prompt impression or outcome.
Authentication
PushWave Public Key
Rate limit
60/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
eventRequired | body | impression | allowed | dismissed | blocked | Prompt event. type is accepted as an alias. |
url | body | URL | Page on which the event occurred. page_url is accepted as an alias. |
ip | body | string | Optional visitor IP. Defaults to the request IP. |
curl --request POST \
--url 'https://app.k2mailer.com/api/pushwave/prompt-event' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"event": "allowed",
"url": "https://example.com/"
}'{
"success": true
}Tracking
3 operationsPOST/api/track/viewRecord a notification view
Record that a subscriber viewed a PushWave broadcast.
/api/track/viewRecord a notification view
Record that a subscriber viewed a PushWave broadcast.
Authentication
PushWave Public Key
Rate limit
120/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
broadcast_idRequired | body | integer | Broadcast ID for this site. |
subscriber_idRequired | body | integer | Subscriber ID for this site. |
curl --request POST \
--url 'https://app.k2mailer.com/api/track/view' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"broadcast_id": 314,
"subscriber_id": 9021
}'{
"ok": true
}POST/api/track/dismissedRecord prompt dismissal
Record that the site opt-in prompt was dismissed.
/api/track/dismissedRecord prompt dismissal
Record that the site opt-in prompt was dismissed.
Authentication
PushWave Public Key
Rate limit
120/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
url | body | URL | Page on which the prompt was dismissed. |
ip | body | string | Optional visitor IP. Defaults to the request IP. |
Important
- This tracks opt-in prompt dismissal, not the closing of a delivered notification.
curl --request POST \
--url 'https://app.k2mailer.com/api/track/dismissed' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://example.com/pricing"
}'{
"ok": true
}POST/api/track/pageviewRecord a subscriber page view
Associate a page view with an existing PushWave subscriber.
/api/track/pageviewRecord a subscriber page view
Associate a page view with an existing PushWave subscriber.
Authentication
PushWave Public Key
Rate limit
120/min/IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The browser-safe site Public Key beginning with pk_. |
subscriber_idRequired | body | integer | Subscriber ID for this site. |
urlRequired | body | URL | Viewed page URL. |
referrer | body | URL | Optional referring page. |
curl --request POST \
--url 'https://app.k2mailer.com/api/track/pageview' \
--header 'X-Api-Key: pk_YOUR_PUBLIC_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"subscriber_id": 9021,
"url": "https://example.com/features",
"referrer": "https://example.com/"
}'{
"ok": true
}Broadcasts
5 operationsGET/api/pushwave/broadcastsList broadcasts
Return paginated broadcasts for the site identified by the Secret Key.
/api/pushwave/broadcastsList broadcasts
Return paginated broadcasts for the site identified by the Secret Key.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
search | query | string | Search broadcast title or message. |
status | query | string | Filter by broadcast status. |
from | query | date | Created-at lower bound. |
to | query | date | Created-at upper bound. |
per_page | query | integer | Results per page, maximum 100. |
page | query | integer | Page number. |
curl --request GET \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts?status=draft&per_page=25&page=1' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json'{
"data": [
{
"id": 314,
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"status": "draft",
"audience_count": 0,
"stats": {
"sent": 0,
"views": 0,
"clicks": 0,
"view_rate": 0,
"click_rate": 0
},
"created_at": "2026-07-24T09:30:00Z",
"updated_at": "2026-07-24T09:30:00Z"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 25,
"total": 1,
"from": 1,
"to": 1
},
"links": {
"first": "https://app.k2mailer.com/api/pushwave/broadcasts?page=1",
"last": "https://app.k2mailer.com/api/pushwave/broadcasts?page=1",
"prev": null,
"next": null
}
}POST/api/pushwave/broadcastsCreate a broadcast
Create a draft, send immediately, or schedule a site broadcast.
/api/pushwave/broadcastsCreate a broadcast
Create a draft, send immediately, or schedule a site broadcast.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 201
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
titleRequired | body | string | Notification title, maximum 255 characters. |
messageRequired | body | string | Notification message, maximum 2,000 characters. |
urlRequired | body | URL | Click-through URL, maximum 2,000 characters. |
action | body | draft | send_now | schedule | Create behavior. Defaults to draft. |
scheduled_at | body | date-time | Future send time. Required when action is schedule. |
schedule_timezone | body | timezone | IANA timezone used for the scheduled time. |
segment_id | body | integer | Tenant-owned PushWave segment ID. |
audience_filters | body | object | Country, browser, device, and subscribed-page filters. |
audience_filters.country_codes | body | string[] | Two-letter country codes. |
audience_filters.browsers | body | string[] | Browser names, each up to 100 characters. |
audience_filters.device_types | body | string[] | desktop, mobile, or tablet values. |
audience_filters.subscribed_page | body | string | Subscribed-page filter, maximum 2,000 characters. |
icon_url | body | URL | Notification icon. |
show_large_image | body | boolean | Enable the large image. |
large_image_url | body | URL | Large image URL. |
multi_action_enabled | body | boolean | Enable notification action buttons. |
actions | body | object[] | Up to two action buttons with title and URL. |
utm_enabled | body | boolean | Append UTM parameters to click URLs. |
utm_source | body | string | UTM source, maximum 255 characters. |
utm_medium | body | string | UTM medium, maximum 255 characters. |
utm_campaign | body | string | UTM campaign, maximum 255 characters. |
utm_term | body | string | UTM term, maximum 255 characters. |
utm_content | body | string | UTM content, maximum 255 characters. |
notification_duration_enabled | body | boolean | Enable the custom notification duration. |
duration_days | body | integer | Duration days from 0 to 28. |
duration_hours | body | integer | Duration hours from 0 to 23. |
duration_minutes | body | integer | Duration minutes from 0 to 59. |
notif_tag | body | string | Notification replacement tag, maximum 128 characters. |
renotify | body | boolean | Notify again when replacing the same tag. |
silent | body | boolean | Request silent delivery. |
require_interaction | body | boolean | Keep the notification visible until interaction. |
badge_url | body | URL | Notification badge image. |
vibrate_pattern | body | integer[] | string | Positive vibration durations as an array or comma-separated string. |
notif_timestamp | body | integer | date-time | Notification timestamp as milliseconds or a parseable date. |
notif_dir | body | auto | ltr | rtl | Notification text direction. |
Important
- send_now returns HTTP 202. draft and schedule return HTTP 201.
curl --request POST \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"action": "draft",
"icon_url": "https://example.com/icon.png",
"audience_filters": {
"country_codes": [
"PK",
"US"
],
"device_types": [
"desktop",
"mobile"
]
},
"utm_enabled": true,
"utm_source": "pushwave",
"utm_medium": "web-push",
"utm_campaign": "product-update"
}'{
"message": "Broadcast created as draft.",
"data": {
"id": 314,
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"status": "draft",
"audience_count": 0,
"stats": {
"sent": 0,
"views": 0,
"clicks": 0,
"view_rate": 0,
"click_rate": 0
},
"created_at": "2026-07-24T09:30:00Z",
"updated_at": "2026-07-24T09:30:00Z"
}
}GET/api/pushwave/broadcasts/{broadcast}Get a broadcast
Return a broadcast owned by the site resolved from the Secret Key.
/api/pushwave/broadcasts/{broadcast}Get a broadcast
Return a broadcast owned by the site resolved from the Secret Key.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
broadcastRequired | path | integer | A broadcast belonging to the site resolved from the Secret Key. |
curl --request GET \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts/314' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json'{
"data": {
"id": 314,
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"status": "draft",
"audience_count": 0,
"stats": {
"sent": 0,
"views": 0,
"clicks": 0,
"view_rate": 0,
"click_rate": 0
},
"created_at": "2026-07-24T09:30:00Z",
"updated_at": "2026-07-24T09:30:00Z"
}
}PATCH/api/pushwave/broadcasts/{broadcast}Update a broadcast
Update a mutable site broadcast. PUT is also accepted.
/api/pushwave/broadcasts/{broadcast}Update a broadcast
Update a mutable site broadcast. PUT is also accepted.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
broadcastRequired | path | integer | A broadcast belonging to the site resolved from the Secret Key. |
title | body | string | Notification title, maximum 255 characters. |
message | body | string | Notification message, maximum 2,000 characters. |
url | body | URL | Click-through URL, maximum 2,000 characters. |
action | body | draft | send_now | schedule | Create behavior. Defaults to draft. |
scheduled_at | body | date-time | Future send time. Required when action is schedule. |
schedule_timezone | body | timezone | IANA timezone used for the scheduled time. |
segment_id | body | integer | Tenant-owned PushWave segment ID. |
audience_filters | body | object | Country, browser, device, and subscribed-page filters. |
audience_filters.country_codes | body | string[] | Two-letter country codes. |
audience_filters.browsers | body | string[] | Browser names, each up to 100 characters. |
audience_filters.device_types | body | string[] | desktop, mobile, or tablet values. |
audience_filters.subscribed_page | body | string | Subscribed-page filter, maximum 2,000 characters. |
icon_url | body | URL | Notification icon. |
show_large_image | body | boolean | Enable the large image. |
large_image_url | body | URL | Large image URL. |
multi_action_enabled | body | boolean | Enable notification action buttons. |
actions | body | object[] | Up to two action buttons with title and URL. |
utm_enabled | body | boolean | Append UTM parameters to click URLs. |
utm_source | body | string | UTM source, maximum 255 characters. |
utm_medium | body | string | UTM medium, maximum 255 characters. |
utm_campaign | body | string | UTM campaign, maximum 255 characters. |
utm_term | body | string | UTM term, maximum 255 characters. |
utm_content | body | string | UTM content, maximum 255 characters. |
notification_duration_enabled | body | boolean | Enable the custom notification duration. |
duration_days | body | integer | Duration days from 0 to 28. |
duration_hours | body | integer | Duration hours from 0 to 23. |
duration_minutes | body | integer | Duration minutes from 0 to 59. |
notif_tag | body | string | Notification replacement tag, maximum 128 characters. |
renotify | body | boolean | Notify again when replacing the same tag. |
silent | body | boolean | Request silent delivery. |
require_interaction | body | boolean | Keep the notification visible until interaction. |
badge_url | body | URL | Notification badge image. |
vibrate_pattern | body | integer[] | string | Positive vibration durations as an array or comma-separated string. |
notif_timestamp | body | integer | date-time | Notification timestamp as milliseconds or a parseable date. |
notif_dir | body | auto | ltr | rtl | Notification text direction. |
Important
- Only draft, scheduled, failed, and failed_partial broadcasts can be changed. Other states return HTTP 409.
curl --request PATCH \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts/314' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"title": "Updated feature announcement",
"message": "The launch date has changed."
}'{
"message": "Broadcast updated.",
"data": {
"id": 314,
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"status": "draft",
"audience_count": 0,
"stats": {
"sent": 0,
"views": 0,
"clicks": 0,
"view_rate": 0,
"click_rate": 0
},
"created_at": "2026-07-24T09:30:00Z",
"updated_at": "2026-07-24T09:30:00Z"
}
}DELETE/api/pushwave/broadcasts/{broadcast}Delete a broadcast
Delete a mutable broadcast belonging to the authenticated site.
/api/pushwave/broadcasts/{broadcast}Delete a broadcast
Delete a mutable broadcast belonging to the authenticated site.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
broadcastRequired | path | integer | A broadcast belonging to the site resolved from the Secret Key. |
Important
- Only draft, scheduled, failed, and failed_partial broadcasts can be deleted.
curl --request DELETE \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts/314' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json'{
"message": "Broadcast deleted."
}Broadcast actions
3 operationsPOST/api/pushwave/broadcasts/{broadcast}/scheduleSchedule a broadcast
Schedule a mutable broadcast for a future time.
/api/pushwave/broadcasts/{broadcast}/scheduleSchedule a broadcast
Schedule a mutable broadcast for a future time.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
broadcastRequired | path | integer | A broadcast belonging to the site resolved from the Secret Key. |
scheduled_atRequired | body | date-time | A future date and time. |
schedule_timezone | body | timezone | IANA timezone for the schedule. |
curl --request POST \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts/314/schedule' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"scheduled_at": "2026-08-01 10:00:00",
"schedule_timezone": "Asia/Karachi"
}'{
"message": "Broadcast scheduled.",
"data": {
"id": 314,
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"status": "scheduled",
"audience_count": 0,
"stats": {
"sent": 0,
"views": 0,
"clicks": 0,
"view_rate": 0,
"click_rate": 0
},
"created_at": "2026-07-24T09:30:00Z",
"updated_at": "2026-07-24T09:30:00Z",
"scheduled_at": "2026-08-01T05:00:00Z"
}
}POST/api/pushwave/broadcasts/{broadcast}/sendSend a broadcast
Queue a mutable broadcast for immediate delivery.
/api/pushwave/broadcasts/{broadcast}/sendSend a broadcast
Queue a mutable broadcast for immediate delivery.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 202
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
broadcastRequired | path | integer | A broadcast belonging to the site resolved from the Secret Key. |
curl --request POST \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts/314/send' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json'{
"message": "Broadcast queued for sending.",
"data": {
"id": 314,
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"status": "sending",
"audience_count": 0,
"stats": {
"sent": 0,
"views": 0,
"clicks": 0,
"view_rate": 0,
"click_rate": 0
},
"created_at": "2026-07-24T09:30:00Z",
"updated_at": "2026-07-24T09:30:00Z"
}
}POST/api/pushwave/broadcasts/{broadcast}/testSend a test notification
Send a test to one site subscriber without starting the broadcast.
/api/pushwave/broadcasts/{broadcast}/testSend a test notification
Send a test to one site subscriber without starting the broadcast.
Authentication
PushWave Secret Key
Rate limit
60/min/credential
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
X-Api-KeyRequired | header | string | The private site Secret Key beginning with sk_. |
broadcastRequired | path | integer | A broadcast belonging to the site resolved from the Secret Key. |
subscriber_id | body | integer | Target tenant-owned subscriber ID. |
endpoint | body | URL | Target tenant-owned browser endpoint. |
Important
- Provide either subscriber_id or endpoint. A target outside the current site is rejected.
curl --request POST \
--url 'https://app.k2mailer.com/api/pushwave/broadcasts/314/test' \
--header 'X-Api-Key: sk_YOUR_SECRET_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"subscriber_id": 9021
}'{
"message": "Test notification sent.",
"data": {
"broadcast": {
"id": 314,
"title": "New feature available",
"message": "See what changed in your dashboard.",
"url": "https://example.com/product-update",
"status": "draft",
"audience_count": 0,
"stats": {
"sent": 0,
"views": 0,
"clicks": 0,
"view_rate": 0,
"click_rate": 0
},
"created_at": "2026-07-24T09:30:00Z",
"updated_at": "2026-07-24T09:30:00Z"
},
"subscriber_id": 9021,
"success": true
}
}AI conversations
AI Chat Assistant API
Power the public chat widget or export bots, conversations, messages, and leads.
- Authentication
- Public bot token or Bearer personal token
- Bot installation settings or AI Chat Assistant → API Tokens.
- Base URL
- https://app.k2mailer.com
- 6–60 requests per minute, depending on the endpoint
Public widget
7 operationsGET/api/chat/{public_token}/configGet widget configuration
Return public visual, copy, launcher, and escalation settings for a bot.
/api/chat/{public_token}/configGet widget configuration
Return public visual, copy, launcher, and escalation settings for a bot.
Authentication
AI bot public token
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
public_tokenRequired | path | string | The bot public token from its installation settings. |
curl --request GET \
--url 'https://app.k2mailer.com/api/chat/BOT_PUBLIC_TOKEN/config' \
--header 'Accept: application/json'{
"status": "active",
"bot_display_name": "K2 Assistant",
"greeting_message": "How can I help?",
"primary_color": "#0052CC",
"position": "right",
"show_branding": true,
"fallback_message": "I could not find that in the knowledge base.",
"lead_capture_after": 3,
"suggested_questions": [
"How do I start?",
"What plans are available?"
],
"show_escalation": true
}POST/api/chat/{public_token}/session/startStart or resume a session
Start a chat session or validate and resume an existing session token.
/api/chat/{public_token}/session/startStart or resume a session
Start a chat session or validate and resume an existing session token.
Authentication
AI bot public token
Rate limit
20/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
public_tokenRequired | path | string | The bot public token from its installation settings. |
OriginRequired | header | URL | A domain allowed in the bot settings. |
existing_session_token | body | string | A prior 64-character session token to resume. |
Important
- A resumed session must belong to the same bot and match its stored visitor IP and origin context.
curl --request POST \
--url 'https://app.k2mailer.com/api/chat/BOT_PUBLIC_TOKEN/session/start' \
--header 'Origin: https://your-site.example' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{}'{
"session_token": "f3d9b46b973f7ac76dd8f916c1c4e3a3524f975ad142df6c47c0d8191a0c227b"
}POST/api/chat/{public_token}/leadCapture a lead
Attach a verified-format email address to an active chat session.
/api/chat/{public_token}/leadCapture a lead
Attach a verified-format email address to an active chat session.
Authentication
AI bot public token
Rate limit
6/min
Success
HTTP 201
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
public_tokenRequired | path | string | The bot public token from its installation settings. |
OriginRequired | header | URL | A domain allowed in the bot settings. |
session_tokenRequired | body | string | The 64-character lowercase hexadecimal chat session token. |
emailRequired | body | Lead email address with a valid DNS domain. | |
website | body | string | Spam honeypot. Legitimate clients must leave this empty. |
Important
- The website field is a spam honeypot and should not be populated by legitimate clients.
curl --request POST \
--url 'https://app.k2mailer.com/api/chat/BOT_PUBLIC_TOKEN/lead' \
--header 'Origin: https://your-site.example' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"session_token": "f3d9b46b973f7ac76dd8f916c1c4e3a3524f975ad142df6c47c0d8191a0c227b",
"email": "visitor@example.com"
}'{
"captured": true,
"email": "visitor@example.com"
}POST/api/chat/{public_token}/messageSend a message
Send a visitor message and receive the assistant reply as JSON.
/api/chat/{public_token}/messageSend a message
Send a visitor message and receive the assistant reply as JSON.
Authentication
AI bot public token
Rate limit
20/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
public_tokenRequired | path | string | The bot public token from its installation settings. |
OriginRequired | header | URL | A domain allowed in the bot settings. |
session_tokenRequired | body | string | The 64-character lowercase hexadecimal chat session token. |
messageRequired | body | string | Visitor message, maximum 2,000 characters. |
Important
- The workspace monthly message limit can return HTTP 429.
curl --request POST \
--url 'https://app.k2mailer.com/api/chat/BOT_PUBLIC_TOKEN/message' \
--header 'Origin: https://your-site.example' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"session_token": "f3d9b46b973f7ac76dd8f916c1c4e3a3524f975ad142df6c47c0d8191a0c227b",
"message": "How do I create a campaign?"
}'{
"message": "Open Campaigns, choose Create campaign, then select your list.",
"message_id": 712,
"citations": [],
"lead_capture_required": false,
"lead_prompt_message": null,
"awaiting_lead_email": false
}GET/api/chat/{public_token}/streamStream an assistant reply
Receive the assistant reply incrementally as a Server-Sent Events stream.
/api/chat/{public_token}/streamStream an assistant reply
Receive the assistant reply incrementally as a Server-Sent Events stream.
Authentication
AI bot public token
Rate limit
20/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
public_tokenRequired | path | string | The bot public token from its installation settings. |
OriginRequired | header | URL | A domain allowed in the bot settings. |
session_tokenRequired | query | string | The 64-character lowercase hexadecimal chat session token. |
messageRequired | query | string | URL-encoded visitor message, maximum 2,000 characters. |
Important
- Set Accept: text/event-stream and process each data event until done is true.
curl --request GET \
--url 'https://app.k2mailer.com/api/chat/BOT_PUBLIC_TOKEN/stream?session_token=f3d9b46b973f7ac76dd8f916c1c4e3a3524f975ad142df6c47c0d8191a0c227b&message=How+do+I+create+a+campaign%3F' \
--header 'Origin: https://your-site.example' \
--header 'Accept: text/event-stream'data: {"chunk":"Open "}
data: {"chunk":"Campaigns"}
data: {"done":true,"citations":[],"message_id":712,"session_token":"f3d9…227b","origin_domain":"your-site.example"}
POST/api/chat/{public_token}/rateRate an assistant message
Save positive or negative feedback for an assistant response.
/api/chat/{public_token}/rateRate an assistant message
Save positive or negative feedback for an assistant response.
Authentication
AI bot public token
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
public_tokenRequired | path | string | The bot public token from its installation settings. |
OriginRequired | header | URL | A domain allowed in the bot settings. |
session_tokenRequired | body | string | The 64-character lowercase hexadecimal chat session token. |
message_idRequired | body | integer | Assistant message in this session. |
ratingRequired | body | -1 | 1 | Negative or positive rating. |
comment | body | string | Optional feedback, maximum 500 characters. |
curl --request POST \
--url 'https://app.k2mailer.com/api/chat/BOT_PUBLIC_TOKEN/rate' \
--header 'Origin: https://your-site.example' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"session_token": "f3d9b46b973f7ac76dd8f916c1c4e3a3524f975ad142df6c47c0d8191a0c227b",
"message_id": 712,
"rating": 1,
"comment": "This answered my question."
}'{
"rated": true,
"rating": 1
}POST/api/chat/{public_token}/escalateRequest escalation
Mark a conversation as requiring human follow-up.
/api/chat/{public_token}/escalateRequest escalation
Mark a conversation as requiring human follow-up.
Authentication
AI bot public token
Rate limit
60/min
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
public_tokenRequired | path | string | The bot public token from its installation settings. |
OriginRequired | header | URL | A domain allowed in the bot settings. |
session_tokenRequired | body | string | The 64-character lowercase hexadecimal chat session token. |
curl --request POST \
--url 'https://app.k2mailer.com/api/chat/BOT_PUBLIC_TOKEN/escalate' \
--header 'Origin: https://your-site.example' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"session_token": "f3d9b46b973f7ac76dd8f916c1c4e3a3524f975ad142df6c47c0d8191a0c227b"
}'{
"escalated": true
}Developer exports
5 operationsGET/api/v1/botsList bots
Return bots visible to a personal API token with bots:read permission.
/api/v1/botsList bots
Return bots visible to a personal API token with bots:read permission.
Authentication
AI personal Bearer token
Rate limit
60/min/token+IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
AuthorizationRequired | header | Bearer k2chat_* | A private AI Chat Assistant personal API token. |
page | query | integer | Page number. Returns 20 bots per page. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/bots?page=1' \
--header 'Authorization: Bearer k2chat_YOUR_TOKEN' \
--header 'Accept: application/json'{
"current_page": 1,
"data": [
{
"id": 33,
"name": "Support bot",
"status": "active",
"default_locale": "en",
"monthly_message_count": 125,
"sessions_count": 18,
"leads_count": 4,
"documents_count": 7
}
],
"per_page": 20,
"total": 1
}GET/api/v1/bots/{botId}/sessionsList bot sessions
Return conversations for a bot using conversations:read permission.
/api/v1/bots/{botId}/sessionsList bot sessions
Return conversations for a bot using conversations:read permission.
Authentication
AI personal Bearer token
Rate limit
60/min/token+IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
AuthorizationRequired | header | Bearer k2chat_* | A private AI Chat Assistant personal API token. |
botIdRequired | path | integer | A bot belonging to the personal API token account. |
since | query | date-time | Only sessions updated after this time. |
page | query | integer | Page number. Returns 50 sessions per page. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/bots/33/sessions?since=2026-07-01T00%3A00%3A00Z&page=1' \
--header 'Authorization: Bearer k2chat_YOUR_TOKEN' \
--header 'Accept: application/json'{
"current_page": 1,
"data": [
{
"id": 501,
"bot_id": 33,
"visitor_email": "visitor@example.com",
"origin_domain": "your-site.example",
"locale": "en",
"message_count": 4,
"lead_captured": true,
"escalated": false,
"started_at": "2026-07-24T09:00:00Z",
"last_activity_at": "2026-07-24T09:03:00Z"
}
],
"per_page": 50,
"total": 1
}GET/api/v1/bots/{botId}/sessions/{sessionId}/messagesList session messages
Return messages in a bot session using conversations:read permission.
/api/v1/bots/{botId}/sessions/{sessionId}/messagesList session messages
Return messages in a bot session using conversations:read permission.
Authentication
AI personal Bearer token
Rate limit
60/min/token+IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
AuthorizationRequired | header | Bearer k2chat_* | A private AI Chat Assistant personal API token. |
botIdRequired | path | integer | A bot belonging to the personal API token account. |
sessionIdRequired | path | integer | Session belonging to the requested bot. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/bots/33/sessions/501/messages' \
--header 'Authorization: Bearer k2chat_YOUR_TOKEN' \
--header 'Accept: application/json'[
{
"id": 711,
"role": "user",
"content": "How do I create a campaign?",
"created_at": "2026-07-24T09:01:00Z"
},
{
"id": 712,
"role": "assistant",
"content": "Open Campaigns and choose Create campaign.",
"created_at": "2026-07-24T09:01:02Z"
}
]GET/api/v1/bots/{botId}/sessions/{sessionId}/exportExport a session
Return a conversation export containing session metadata and messages.
/api/v1/bots/{botId}/sessions/{sessionId}/exportExport a session
Return a conversation export containing session metadata and messages.
Authentication
AI personal Bearer token
Rate limit
60/min/token+IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
AuthorizationRequired | header | Bearer k2chat_* | A private AI Chat Assistant personal API token. |
botIdRequired | path | integer | A bot belonging to the personal API token account. |
sessionIdRequired | path | integer | Session belonging to the requested bot. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/bots/33/sessions/501/export' \
--header 'Authorization: Bearer k2chat_YOUR_TOKEN' \
--header 'Accept: application/json'{
"session": {
"id": 501,
"started_at": "2026-07-24T09:00:00Z"
},
"messages": [
{
"role": "user",
"content": "How do I create a campaign?"
},
{
"role": "assistant",
"content": "Open Campaigns and choose Create campaign."
}
]
}GET/api/v1/bots/{botId}/leadsList bot leads
Return captured leads using leads:read permission.
/api/v1/bots/{botId}/leadsList bot leads
Return captured leads using leads:read permission.
Authentication
AI personal Bearer token
Rate limit
60/min/token+IP
Success
HTTP 200
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
AuthorizationRequired | header | Bearer k2chat_* | A private AI Chat Assistant personal API token. |
botIdRequired | path | integer | A bot belonging to the personal API token account. |
since | query | date-time | Only leads created after this time. |
page | query | integer | Page number. Returns 100 leads per page. |
curl --request GET \
--url 'https://app.k2mailer.com/api/v1/bots/33/leads?since=2026-07-01T00%3A00%3A00Z&page=1' \
--header 'Authorization: Bearer k2chat_YOUR_TOKEN' \
--header 'Accept: application/json'{
"current_page": 1,
"data": [
{
"id": 185,
"bot_id": 33,
"session_id": 501,
"email": "visitor@example.com",
"captured_at": "2026-07-24T09:03:00Z"
}
],
"per_page": 100,
"total": 1
}