Download OpenAPI specification:
https://api.kajabi.com
/v1
GET https://api.kajabi.com/v1/version
client_id
and client_secret
are available on the User API Keys section of the Kajabi Admin Portal.Release notes...
0.4.0 (April 11, 2025)
New developer site https://developers.kajabi.com
Add resource attribute definitions to docs
Improve docs with comprehensive response examples using a variety of request parameters
Add checkout url to offer resource
Add endpoints for forms, including form submission
Contacts related offers are linked by url vs listed by id
Add publishing_option to module/lesson public api
Add internal_title and payment info attributes to offer serializer
Add refresh_token to oauth/token response
Add transactions endpoints
Add lessons.media relationship for courses
0.3.0 (March 19, 2025)
Add oauth revoke endpoint
Improve docs for oauth token credential grant
Add contacts filter params: search, has_product_id, has_tag_id, has_offer_id
Add customers endpoints
Add courses endpoints
Add example responses to docs for page and filter parameters
Improve docs for success responses
Add forbidden error response examples
Improve docs for granting and revoking offers
0.2.0 (October 25, 2024)
Credential exchange using Kajabi account api key/secret
Add contacts offers relation endpoints to grant/revoke offers
Add contacts relationship to offers
Add products relationship to offers
Add products endpoints
Add offers endpoints
0.1.3 (October 21, 2024)
Add contact tag endpoints
Add contacts tag relation endpoints to add/remove tags
Document /contacts/{id}?include= parameter with tags example```
0.1.2 (October 11, 2024)
Add /api/v1/custom_fields endpoint
Add clarify filters for contacts in the openapi spec
0.1.1 (October 3, 2024)
Add sorting to contacts
Add sparse fields to contacts
Add filters to contacts list endpoint
0.1.0 (July 22, 2024)
Add contacts endpoints
Add sites endpoints
Add me endpoint for current user
Add version endpoint
Add oauth/token endpoint to authenticate with username/password
access_token
and refresh_token
There are three ways to exchange parameters for tokens
client_id
and client_secret
refresh_token
username
and password
(client credentials is preferred)Only include params: client_id
, client_secret
, and grant_type
.
grant_type
param value must be: client_credentials
Only include params: refresh_token
and grant_type
.
grant_type
param value must be: refresh_token
refresh_token
must be a unexpired JWT token, from a prior client credential token grant.Only include params: username
and password
.
A successful response will provide access_token
and refresh_token
values.
access_token
in your Authorization
header as a "Bearer" token to make authenticated requests to the API. E.g. GET https://api.kajabi.com/v1/me
refresh_token
to exchange for a new access_token
when it expires.v1/oauth/revoke
endpoint to "log out".access_token
(string) - The access token for the API sessionrefresh_token
(string) - The refresh token for the API sessiontoken_type
(string) - The type of token, always Bearer
expires_in
(integer) - The number of seconds the access token will be valid forusername | string |
password | string |
client_id | string |
client_secret | string |
grant_type | string |
scope | string |
refresh_token | string |
{- "access_token": "string",
- "refresh_token": "string",
- "token_type": "string",
- "expires_in": 0
}
access_token
and refresh_token
Either token may be provided to "log out" of the API session. Both tokens we be invalidated.
token
with your access_token
or refresh_token
Authorization
header as Bearer access_token
to authenticate the request.token required | string |
Create a contact for a site.
external_user_id
attribute.Request body must include a site
relationship.
Example request body:
{
"data": {
"type": "contacts",
"attributes": {
"name": "John Doe",
"email": "[email protected]"
},
"relationships": {
"site": {
"data": {
"type": "sites",
"id": "123"
}
}
}
}
}
Response will include the newly created contact resource.
{
"data": {
"id": "456",
"type": "contacts",
"attributes": {
"name": "John Doe",
"email": "[email protected]",
"address_line_1": null,
"address_line_2": null,
"address_city": null,
"address_country": null,
"address_state": null,
"address_zip": null,
"phone_number": null,
"business_number": null,
"subscribed": false,
"external_user_id": null,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
}
required | object |
{- "data": {
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "subscribed": true,
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "external_user_id": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}
}
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "subscribed": true,
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "external_user_id": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "customer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offers": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}, - "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "tags": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}, - "links": {
- "customer": "string"
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
List of contacts, we recommended filtering by site.
Use the filter[site_id]
parameter to filter contacts by site:
GET /v1/contacts?filter[site_id]=123
Response will include only contacts for the specified site
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "John Smith",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[search]
parameter along with filter[site_id]
to search contacts by name or email:
GET /v1/contacts?filter[site_id]=123&filter[search]=smith
Response will include only matching contacts for the specified site
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "John Smith",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the use_indexed_data
parameter along with filter[site_id]
and filter[search]
to search contacts using an alternative search algorithm:
GET /v1/contacts?filter[site_id]=123&filter[search]=smith&use_indexed_data=true
Response will include matching contacts using the indexed search algorithm
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "John Smith",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[site_id]
parameter along with pagination parameters page[number]
and page[size]
to get paginated results for a specific site:
GET /v1/contacts?filter[site_id]=123&page[number]=2&page[size]=10
Response will include paginated contacts for the specified site along with pagination metadata
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "John Smith",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}],
"links": {
"self": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&page[number]=2&page[size]=10",
"first": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&page[number]=1&page[size]=10",
"prev": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&page[number]=1&page[size]=10",
"next": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&page[number]=3&page[size]=10",
"last": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Sorting by created_at in ascending order (oldest first)
GET /v1/contacts?filter[site_id]=123&sort=created_at
Use the sort
parameter along with filter[site_id]
to get sorted results for a specific site:
GET /v1/contacts?filter[site_id]=123&sort=name
GET /v1/contacts?filter[site_id]=123&sort=-email
Response will include sorted contacts for the specified site
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the fields[contacts]
parameter along with filter[site_id]
to get specific fields for contacts in a site:
GET /v1/contacts?filter[site_id]=123&fields[contacts]=name,email
Response will include only requested fields for contacts in the specified site
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[site_id]
parameter along with filter[has_offer_id]
to get contacts who have been granted a specific offer
GET /v1/contacts?filter[site_id]=123&filter[has_offer_id]=789
Response will include only contacts from the specified site who have been granted the offer
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[site_id]
parameter along with filter[has_product_id]
to get contacts who have purchased a specific product
GET /v1/contacts?filter[site_id]=123&filter[has_product_id]=789
Response will include only contacts from the specified site who have purchased the product
{
"data": [{
"id": "456",
"type": "contacts",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[site_id]
parameter along with filter[has_tag_id]
to get contacts who have a specific tag
GET /v1/contacts?filter[site_id]=123&filter[has_tag_id]=456
Response will include only contacts from the specified site who have the tag
{
"data": [{
"id": "789",
"type": "contacts",
"attributes": {
"name": "Bob Jones",
"email": "[email protected]",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
You can combine multiple parameters to filter, search, paginate and format the response:
GET /v1/contacts?filter[site_id]=123&filter[has_tag_id]=456&filter[search]=smith&use_indexed_data=true&page[number]=1&page[size]=10&fields[contacts]=name,email
Response will include paginated contacts matching all filters with only requested fields
{
"data": [{
"id": "789",
"type": "contacts",
"attributes": {
"name": "John Smith",
"email": "[email protected]"
}
}],
"links": {
"self": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&filter[has_tag_id]=456&filter[search]=smith&use_indexed_data=true&page[number]=1&page[size]=10&fields[contacts]=name,email",
"first": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&filter[has_tag_id]=456&filter[search]=smith&use_indexed_data=true&page[number]=1&page[size]=10&fields[contacts]=name,email",
"prev": null,
"next": null,
"last": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&filter[has_tag_id]=456&filter[search]=smith&use_indexed_data=true&page[number]=1&page[size]=10&fields[contacts]=name,email"
},
"meta": {
"total_pages": 1,
"total_count": 1,
"current_page": 1
}
}
sort | string Sort order, use: name, email, created_at, for descending order use '-' e.g. &sort=-name |
page[number] | number |
page[size] | number Number of documents |
fields[contacts] | string Sparse fields, use: name, email for example ?fields[contacts]=name,email |
filter[site_id] | string It is recommended to always filter by site_id, for example ?filter[site_id]=111. This param is required when using the following params: search, has_offer_id, has_product_id, has_tag_id. Also, it is required for use with use_indexed_data param |
use_indexed_data | string Alternative algorithm for searching/filtering (in some cases performs faster), for example ?use_indexed_data=true |
filter[external_user_id_cont] | string contains filter, for example ?filter[external_user_id_cont]=123 |
filter[external_user_id_eq] | string equals filter, for example ?filter[external_user_id_eq]=234 |
filter[external_user_id_start] | string starts with filter, for example ?filter[external_user_id_start]=345 |
filter[email_cont] | string deprecated, use filter[search] |
filter[email_eq] | string deprecated, use filter[search] |
filter[email_start] | string deprecated use filter[search] |
filter[name_cont] | string deprecated, use filter[search] |
filter[name_eq] | string deprecated, use filter[search] |
filter[name_start] | string deprecated, use filter[search] |
filter[search] | string Filter with fuzzy search of name/email, for example ?filter[search]=alexa |
filter[has_offer_id] | string Filter based on granted offer, for example ?filter[has_offer_id]=111 |
filter[has_product_id] | string Filter based on product purchase, for example ?filter[has_product_id]=222 |
filter[has_tag_id] | string Filter based on product purchase, for example ?filter[has_tag_id]=333 |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "subscribed": true,
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "external_user_id": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "customer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offers": {
- "links": {
- "self": "string"
}
}, - "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "tags": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}, - "links": {
- "customer": "string"
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
Show details for a contact
name
(string) - The name of the contactemail
(string) - The email of the contact, must be a valid and deliverable email addressaddress_line_1
(string) - The first line of the contact's addressaddress_line_2
(string) - The second line of the contact's addressaddress_city
(string) - The city of the contact's addressaddress_country
(string) - The country of the contact's addressaddress_state
(string) - The state of the contact's addressaddress_zip
(string) - The zip code of the contact's addressphone_number
(string) - The phone number of the contactbusiness_number
(string) - The business phone number of the contactsubscribed
(boolean) - Whether the contact has opted in to receive marketing communications from the siteexternal_user_id
(string) - The external user ID of the contact/customer; this field is only updatable if the contact has been granted an offer or made a purchasecreated_at
(string) - The date and time the contact was createdupdated_at
(string) - The date and time the contact was last updatedUse the include
parameter to include related resources in the response:
GET /v1/contacts/123?include=offers,tags,customer
Response will include the related contact offers, tags and customer resources
{
"data": {
"id": "123",
"type": "contacts",
"attributes": {
"name": "John Smith",
"email": "[email protected]",
"address_line_1": null,
"address_line_2": null,
"address_city": null,
"address_country": null,
"address_state": null,
"address_zip": null,
"phone_number": null,
"business_number": null,
"subscribed": false,
"external_user_id": null,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"links": {
"customer": "https://api.kajabi.com/v1/customers/321"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
},
"offers": {
"links": {
"data": [
{ "id": "456", "type": "offers" }
],
"self": "https://api.kajabi.com/v1/contacts/123/relationships/offers"
}
},
"tags": {
"data": [
{ "id": "789", "type": "contact_tags" }
],
"links": {
"self": "https://api.kajabi.com/v1/contacts/123/relationships/tags"
}
},
"customer": {
"data": {
"id": "321",
"type": "customers"
}
}
}
},
"included": [
{
"id": "456",
"type": "offers",
"attributes": {
"name": "Offer 1",
"description": "Offer 1 description",
"internal_title": "Offer 1",
"price_in_cents": 0,
"payment_type": "free",
"token": "offer_123",
"payment_method": "none",
"price_description": "Free",
"checkout_url": "https://mywebsite.com/offers/456",
"recurring_offer": false,
"subscription": false,
"one_time": true,
"single": false,
"free": true
}
},
{
"id": "789",
"type": "contact_tags",
"attributes": {
"name": "Tag Name"
}
},
{
"id": "321",
"type": "customers",
"attributes": {
"name": "John Smith",
"email": "[email protected]",
"avatar": null,
"external_user_id": "cust_123",
"public_bio": null,
"public_location": null,
"public_website": null,
"socials": null,
"net_revenue": "0.0",
"sign_in_count": 0,
"last_request_at": null,
"bounced_at": null,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
}
]
}
Use the fields[contacts]
parameter to get specific fields for a contact:
GET /v1/contacts/123?fields[contacts]=name,email
Response will include only requested fields for the contact
{
"data": {
"id": "123",
"type": "contacts",
"attributes": {
"name": "John Smith",
"email": "[email protected]"
}
}
}
You can combine multiple parameters to include related resources and get specific fields for a contact:
GET /v1/contacts/123?include=customer&fields[contacts]=email&fields[customers]=net_revenue
Response will include the related customer resource and only requested fields for the contact and customer
{
"data": {
"id": "123",
"type": "contacts",
"attributes": {
"email": "[email protected]"
},
"relationships": {}
},
"included": [
{
"id": "321",
"type": "customers",
"attributes": {
"net_revenue": "0.0"
}
}
]
}
id required | string |
include | string with ?include=offers,tags,customer the response will include the related contact offers, tags and customer resources |
fields[contacts] | string Sparse fields, use: name, email for example ?fields[contacts]=name,email |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "subscribed": true,
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "external_user_id": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "customer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offers": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}, - "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "tags": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}, - "links": {
- "customer": "string"
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
external_user_id
attribute.Example request body:
{
"data": {
"type": "contacts",
"id": "456",
"attributes": {
"phone_number": "12134567890"
}
}
}
Response will include the update contact resource.
{
"data": {
"id": "456",
"type": "contacts",
"attributes": {
"name": "John Doe",
"email": "[email protected]",
"address_line_1": null,
"address_line_2": null,
"address_city": null,
"address_country": null,
"address_state": null,
"address_zip": null,
"phone_number": "12134567890",
"business_number": null,
"subscribed": false,
"external_user_id": null,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
}
id required | string |
required | object |
object |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "subscribed": true,
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "external_user_id": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string",
- "created_at": "string",
- "updated_at": "string"
}
}, - "relationships": {
- "tags": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}
}
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "subscribed": true,
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "external_user_id": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "customer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offers": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}, - "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "tags": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}, - "links": {
- "customer": "string"
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
Get the contact's relationship to offers (granted).
Response is a list of resource identifiers
{
"data": [
{ "type": "offers", "id": "123" },
{ "type": "offers", "id": "456" }
]
}
The related tag resources are available using the GET api/v1/offers
endpoint.
The resource identifier includes the offer id and type.
Example URLs: /api/v1/offers/123
, /api/v1/offers/456
contact_id required | string |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
Create an offer grant for a contact which results in creating a new customer record for your contact.
In the request body inlcude offer resource identifier(s), id: OFFER_ID
, type: "offers"
.
To skip sending a welcome email to the customer include a meta
object in the request body.
{ "data": [{"type": "offers", "id": "123"}], "meta": {"send_customer_welcome_email": false}}
The meta
attribute send_customer_welcome_email
as false
will prevent sending the welcome email.
(The default behavior is to send the welcome email.)
contact_id required | string |
required | Array of objects (resource_identifier) |
object |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "meta": {
- "send_customer_welcome_email": true
}
}
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
Revoke offer grant(s) using a list of resource identifiers
In the request body inlcude offer resource identifier(s), id: OFFER_ID
, type: "offers"
.
{ "data": [{"type": "offers", "id": "123"}] }
contact_id required | string |
required | Array of objects (resource_identifier) |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
Replace offer grants (grants and revokes offers to/from contact) using a list of resource identifiers
In the request body inlcude offer resource identifier(s), id: OFFER_ID
, type: "offers"
.
{ "data": [{"type": "offers", "id": "456"}, {"type": "offers", "id": "789"}] }
contact_id required | string |
required | Array of objects (resource_identifier) |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
List of courses that can be offered to a contact or purchased
Use the page[number]
and page[size]
query parameters to paginate results:
GET /v1/courses?page[number]=1&page[size]=10
GET /v1/courses?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://api.kajabi.com/v1/courses?page[number]=2&page[size]=10",
"first": "https://api.kajabi.com/v1/courses?page[number]=1&page[size]=10",
"prev": "https://api.kajabi.com/v1/courses?page[number]=1&page[size]=10",
"next": "https://api.kajabi.com/v1/courses?page[number]=3&page[size]=10",
"last": "https://api.kajabi.com/v1/courses?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Use the sort
parameter to sort the results:
GET /v1/courses?sort=title
GET /v1/courses?sort=-title
Response will include courses sorted by the specified field
{
"data": [
{
"id": "123",
"type": "courses",
"attributes": {
"title": "Advanced Marketing",
"description": "Master level marketing course",
"status": "active"
}
},
{
"id": "456",
"type": "courses",
"attributes": {
"title": "Marketing Basics",
"description": "Introduction to marketing",
"status": "active"
}
}
]
}
Use the fields
parameter to request only specific attributes:
GET /v1/courses?fields[courses]=title,thumbnail_url
Response will only include requested fields
{
"data": [{
"id": "123",
"type": "courses",
"attributes": {
"title": "Marketing Fundamentals",
"thumbnail_url": "https://example.com/thumbnail.jpg"
}
}]
}
Use the filter[site_id]
parameter to get courses for a specific site:
GET /v1/courses?filter[site_id]=123
Response will only include courses for that site
{
"data": [{
"id": "456",
"type": "courses",
"attributes": {
"title": "Marketing Fundamentals",
"description": "Introduction to marketing concepts",
"status": "active"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[title_cont]
parameter to find courses where the title contains specific text:
GET /v1/courses?filter[title_cont]=marketing
Response will include courses with matching titles
{
"data": [{
"id": "456",
"type": "courses",
"attributes": {
"title": "Marketing Fundamentals",
"description": "Introduction to marketing concepts",
"status": "active"
}
}]
}
Use the filter[description_cont]
parameter to find courses where the description contains specific text:
GET /v1/courses?filter[description_cont]=marketing
Response will include courses with matching descriptions
{
"data": [{
"id": "456",
"type": "courses",
"attributes": {
"title": "Marketing Fundamentals",
"description": "Introduction to marketing concepts and strategies",
"status": "active"
}
}]
}
You can combine pagination, sparse fields, filtering and sorting in a single request:
GET /v1/courses?page[number]=1&page[size]=10&filter[site_id]=123&sort=title&fields[courses]=title,thumbnail_url
Response will include pagination, sorted filtered results with requested fields
{
"data": [{
"id": "456",
"type": "courses",
"attributes": {
"title": "Advanced Marketing",
"thumbnail_url": "https://example.com/thumbnail1.jpg"
}
},
{
"id": "789",
"type": "courses",
"attributes": {
"title": "Marketing Basics",
"thumbnail_url": "https://example.com/thumbnail2.jpg"
}
}],
"links": {
"self": "https://api.kajabi.com/v1/courses?page[number]=1&page[size]=10&filter[site_id]=123&sort=title&fields[courses]=title,thumbnail_url",
"first": "https://api.kajabi.com/v1/courses?page[number]=1&page[size]=10&filter[site_id]=123&sort=title&fields[courses]=title,thumbnail_url",
"next": "https://api.kajabi.com/v1/courses?page[number]=2&page[size]=10&filter[site_id]=123&sort=title&fields[courses]=title,thumbnail_url",
"last": "https://api.kajabi.com/v1/courses?page[number]=3&page[size]=10&filter[site_id]=123&sort=title&fields[courses]=title,thumbnail_url"
},
"meta": {
"total_pages": 3,
"total_count": 25,
"current_page": 1
}
}
sort | string Sort order, use: title, for descending order use '-' e.g. &sort=-title |
page[number] | number |
page[size] | number Number of documents |
fields[courses] | string Partial attributes as specified, e.g. fields[courses]=title,thumbnail_url |
filter[site_id] | string Filter by site_id, for example ?filter[site_id]=111 |
filter[title_cont] | string Filter by title contains, for example ?filter[title_cont]=marketing |
filter[description_cont] | string Filter by description contains, for example ?filter[description_cont]=marketing |
filter[publish_status_eq] | string Filter by publish status, for example ?filter[publish_status_eq]=published |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "created_at": "string",
- "title": "string",
- "description": "string",
- "thumbnail_url": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
Details of a course that can be offered to a contact or purchased
created_at
(string) - The date and time the course was createdtitle
(string) - The title of the coursedescription
(string) - The description of the coursethumbnail_url
(string) - The URL of the course thumbnailUse the include
query parameter to load related resources:
GET /v1/courses/123?include=modules,lessons,lessons.media,offers
Response will include the requested related resources (Note: The responses listed within the "included" array will also include the relationships for each resource)
{
"data": {
"id": "123",
"type": "courses",
"attributes": {
"created_at": "2024-08-06T05:30:38.669Z",
"title": "Advanced Marketing",
"description": "Master level marketing course",
"thumbnail_url": "https://example.com/thumbnail.jpg"
},
"relationships": {
"modules": {
"data": [{
"id": "456",
"type": "modules"
}]
},
"lessons": {
"data": [{
"id": "789",
"type": "lessons"
}]
},
"offers": {
"data": [{
"id": "101",
"type": "offers"
}]
}
},
"included": [{
"id": "456",
"type": "modules",
"attributes": {
"title": "Marketing Fundamentals",
"description": "Introduction to marketing concepts",
"position": 1,
"poster_image_url": "https://example.com/poster.jpg",
"publishing_option": "published"
}
},
{
"id": "789",
"type": "lessons",
"attributes": {
"title": "Marketing Basics",
"position": 1,
"status": "published",
"publishing_option": "published"
}
},
{
"id": "202",
"type": "media",
"attributes": {
"duration_in_minutes": 1,
}
},
{
"id": "101",
"type": "offers",
"attributes": {
"price": 100.0,
"currency": "USD",
"status": "active"
}
}]
}
}
Modules are part of Kajabi's course structure: courses contain modules and modules contain lessons
title
(string) - A required field that represents the name or heading of the module. This is used to:description
(string) - An optional text field that provides additional information about the module's content. This can be used to:position
(integer) - A numeric field that determines the order of modules within a course. This:poster_image_url
(string) - A URL to an image that represents the module visually. This:publishing_option
(string) - Controls the visibility and availability of the module. Options include:published
- Module is visible and available to studentsdraft
- Module is hidden and not yet availableLessons can include various types of content: text content (body), videos, audio, quizzes, assessments, and downloads.
title
(string) - A required field that represents the name or heading of the lesson. This:position
(integer) - A numeric field that determines the order of lessons within a module (category). This:status
(string) - An field that tracks the lesson's processing state:ready
- Default state, lesson is ready for useduplicating
- Lesson is being copiedfailed
- An error occurred during processingpublishing_option
(string) - Controls the visibility and availability of the lesson. Options include:draft
- Lesson is hidden and not yet available to studentspublished
- Lesson is visible and available (sets publish_at to current time)drip
- Lesson becomes available after a specified number of dayslocked
- Lesson is locked until certain conditions are met (e.g., completing previous lessons)duration_in_minutes
(float) - The length of a media file (typically video or audio) in minutes.Use the fields
parameter to request only specific attributes:
GET /v1/courses/123?fields[courses]=title,thumbnail_url
Response will only include requested fields
{
"data": {
"id": "123",
"type": "courses",
"attributes": {
"title": "Marketing Fundamentals",
"thumbnail_url": "https://example.com/thumbnail.jpg"
}
}
}
You can combine sparse fields and include in a single request:
GET /v1/courses/123?include=modules,lessons,lessons.media&fields[courses]=title,thumbnail_url&fields[modules]=title&fields[lessons]=title&fields[media]=duration_in_minutes
Response will include related resources with requested fields
{
"data": {
"id": "123",
"type": "courses",
"attributes": {
"title": "Marketing Fundamentals",
"thumbnail_url": "https://example.com/thumbnail.jpg"
},
"relationships": {}
},
"included": [{
"id": "456",
"type": "modules",
"attributes": {
"title": "Marketing Basics"
}
},
{
"id": "789",
"type": "lessons",
"attributes": {
"title": "Marketing Strategies"
}
},
{
"id": "101",
"type": "media",
"attributes": {
"duration_in_minutes": 30
}
}]
}
id required | string |
include | string Load the related resources, for example ?include=modules,lessons,lessons.media |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "created_at": "string",
- "title": "string",
- "description": "string",
- "thumbnail_url": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offers": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}, - "modules": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}, - "lessons": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}
}, - "links": {
- "self": "string",
- "current": "string"
}, - "included": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "title": "string",
- "description": "string",
- "internal_title": "string",
- "currency": "string",
- "price_in_cents": 0,
- "payment_type": "string",
- "token": "string",
- "payment_method": "string",
- "price_description": "string",
- "checkout_url": "string",
- "recurring_offer": true,
- "subscription": true,
- "one_time": true,
- "single": true,
- "free": true
}, - "relationships": { }
}
]
}
List of products (not archived) that can be granted to a contact
Use page[number]
and page[size]
parameters to paginate results:
GET /v1/products?page[number]=1&page[size]=10
GET /v1/products?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://api.kajabi.com/v1/products?page[number]=2&page[size]=10",
"first": "https://api.kajabi.com/v1/products?page[number]=1&page[size]=10",
"prev": "https://api.kajabi.com/v1/products?page[number]=1&page[size]=10",
"next": "https://api.kajabi.com/v1/products?page[number]=3&page[size]=10",
"last": "https://api.kajabi.com/v1/products?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Use the sort
parameter to sort the results:
GET /v1/products?sort=title
GET /v1/products?sort=-title
Response will include products sorted by the specified field
{
"data": [
{
"id": "123",
"type": "products",
"attributes": {
"title": "Advanced Course",
"description": "In-depth training",
"status": "active"
}
},
{
"id": "456",
"type": "products",
"attributes": {
"title": "Beginner Course",
"description": "Introduction to basics",
"status": "active"
}
}
]
}
Use the fields[products]
parameter to request only specific attributes:
GET /v1/products?fields[products]=title,publish_status
Response will only include the requested fields
{
"data": [
{
"id": "123",
"type": "products",
"attributes": {
"title": "Advanced Course",
"publish_status": "published"
}
},
{
"id": "456",
"type": "products",
"attributes": {
"title": "Beginner Course",
"publish_status": "draft"
}
}
]
}
Use the filter[site_id]
parameter to get products for a specific site:
GET /v1/products?filter[site_id]=123
Response will only include products for that site
{
"data": [
{
"id": "456",
"type": "products",
"attributes": {
"title": "Advanced Course",
"description": "In-depth training",
"status": "active",
"publish_status": "published"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
]
}
Use the filter[title_cont]
parameter to find products where the title contains specific text:
GET /v1/products?filter[title_cont]=course
Response will include products with matching titles
{
"data": [{
"id": "456",
"type": "products",
"attributes": {
"title": "Advanced Course",
"description": "In-depth training",
"status": "active",
"publish_status": "published"
}
},
{
"id": "789",
"type": "products",
"attributes": {
"title": "Beginner Course",
"description": "Introduction to basics",
"status": "active",
"publish_status": "published"
}
}]
}
Use the filter[description_cont]
parameter to find products where the description contains specific text:
GET /v1/products?filter[description_cont]=training
Response will include products with matching descriptions
{
"data": [{
"id": "456",
"type": "products",
"attributes": {
"title": "Advanced Course",
"description": "In-depth training program",
"status": "active",
"publish_status": "published"
}
},
{
"id": "789",
"type": "products",
"attributes": {
"title": "Professional Course",
"description": "Professional training and certification",
"status": "active",
"publish_status": "published"
}
}]
}
Use the filter[status_eq]
parameter to find products with a specific status:
GET /v1/products?filter[status_eq]=ready
Response will include products with matching status
{
"data": [{
"id": "456",
"type": "products",
"attributes": {
"title": "Advanced Course",
"description": "In-depth training program",
"status": "ready",
"publish_status": "published"
}
},
{
"id": "789",
"type": "products",
"attributes": {
"title": "Professional Course",
"description": "Professional training and certification",
"status": "ready",
"publish_status": "published"
}
}]
}
You can combine pagination, sorting, sparse fields and filtering in a single request:
GET /v1/products?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[products]=title,publish_status
Response will include paginated and filtered products with sparse fields
{
"data": [
{
"id": "456",
"type": "products",
"attributes": {
"title": "Beginner Course",
"publish_status": "draft"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
],
"links": {
"self": "https://api.kajabi.com/v1/products?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[products]=title,publish_status",
"first": "https://api.kajabi.com/v1/products?page[number]=1&page[size]=10&sort=-title&filter[site_id]=123&fields[products]=title,publish_status",
"prev": "https://api.kajabi.com/v1/products?page[number]=1&page[size]=10&sort=-title&filter[site_id]=123&fields[products]=title,publish_status",
"next": null,
"last": "https://api.kajabi.com/v1/products?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[products]=title,publish_status"
},
"meta": {
"total_pages": 2,
"total_count": 15,
"current_page": 2
}
}
sort | string Sort order, use: title, description, status, for descending order use '-' e.g. &sort=-title |
page[number] | number |
page[size] | number Number of documents |
fields[products] | string Partial attributes as specified, e.g. fields[products]=title,publish_status |
filter[site_id] | string Filter by site_id, for example ?filter[site_id]=111 |
filter[title_cont] | string Filter by title contains, for example ?filter[title_cont]=marketing |
filter[description_cont] | string Filter by description contains, for example ?filter[description_cont]=marketing |
filter[status_eq] | string Filter by status equals, for example ?filter[status_eq]=ready |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "created_at": "string",
- "title": "string",
- "description": "string",
- "status": "string",
- "members_aggregate_count": 0,
- "product_type_name": "string",
- "product_type_id": 0,
- "publish_status": "string",
- "thumbnail_url": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
Show details of a product
Use the fields[products]
parameter to request only specific attributes:
GET /v1/products/123?fields[products]=title,publish_status
Response will only include the requested fields
{
"data": {
"id": "123",
"type": "products",
"attributes": {
"title": "Advanced Course",
"publish_status": "published"
},
"relationships": {}
}
}
id required | string |
fields[products] | string Partial attributes as specified, e.g. fields[products]=title,publish_status |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "created_at": "string",
- "title": "string",
- "description": "string",
- "status": "string",
- "members_aggregate_count": 0,
- "product_type_name": "string",
- "product_type_id": 0,
- "publish_status": "string",
- "thumbnail_url": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
The 'handle' attribute may be used as a key for a contact resource, e.g. custom_1, custom_2, custom_3
Use page[number]
and page[size]
parameters to paginate results:
GET /v1/custom_fields?page[number]=1&page[size]=10
GET /v1/custom_fields?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://app.kajabi.com/api/v1/custom_fields?page[number]=2&page[size]=10",
"first": "https://app.kajabi.com/api/v1/custom_fields?page[number]=1&page[size]=10",
"prev": "https://app.kajabi.com/api/v1/custom_fields?page[number]=1&page[size]=10",
"next": "https://app.kajabi.com/api/v1/custom_fields?page[number]=3&page[size]=10",
"last": "https://app.kajabi.com/api/v1/custom_fields?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Use the filter[site_id]
parameter to get custom fields for a specific site:
GET /v1/custom_fields?filter[site_id]=123
Response will only include custom fields for that site
{
"data": [
{
"id": "123",
"type": "custom_fields",
"attributes": {
"handle": "custom_1",
"title": "Favorite Song",
"type": "TextField",
"required": false
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
]
}
Use the sort
parameter to sort the results:
GET /v1/custom_fields?sort=title
GET /v1/custom_fields?sort=-title
Use the filter[title_cont]
parameter to find custom fields where the title contains specific text:
GET /v1/custom_fields?filter[title_cont]=favorite
Response will include custom fields with matching titles
{
"data": [{
"id": "123",
"type": "custom_fields",
"attributes": {
"handle": "custom_1",
"title": "Favorite Song",
"type": "TextField",
"required": false
}
},
{
"id": "456",
"type": "custom_fields",
"attributes": {
"handle": "custom_2",
"title": "Favorite Movie",
"type": "TextField",
"required": false
}
}]
}
Use the filter[required_eq]
parameter to find custom fields based on their required status:
GET /v1/custom_fields?filter[required_eq]=true
Response will include custom fields that are required
{
"data": [{
"id": "123",
"type": "custom_fields",
"attributes": {
"handle": "custom_1",
"title": "Phone Number",
"type": "TextField",
"required": true
}
}]
}
You can combine pagination, sorting, sparse fields and filtering in a single request:
GET /v1/custom_fields?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[custom_fields]=handle,title
Response will include paginated and filtered custom fields with sparse fields
{
"data": [
{
"id": "456",
"type": "custom_fields",
"attributes": {
"handle": "custom_2",
"title": "Favorite Movie"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
],
"links": {
"self": "https://app.kajabi.com/api/v1/custom_fields?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[custom_fields]=handle,title",
"first": "https://app.kajabi.com/api/v1/custom_fields?page[number]=1&page[size]=10&sort=-title&filter[site_id]=123&fields[custom_fields]=handle,title",
"prev": "https://app.kajabi.com/api/v1/custom_fields?page[number]=1&page[size]=10&sort=-title&filter[site_id]=123&fields[custom_fields]=handle,title",
"next": null,
"last": "https://app.kajabi.com/api/v1/custom_fields?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[custom_fields]=handle,title"
},
"meta": {
"total_pages": 2,
"total_count": 15,
"current_page": 2
}
}
sort | string Sort order, use: title, handle, type, required for descending order use '-' e.g. &sort=-title |
page[number] | number |
page[size] | number Number of documents |
fields[custom_fields] | string Partial attributes as specified, e.g. fields[custom_fields]=handle,title,required |
filter[site_id] | string Filter by site_id, for example ?filter[site_id]=111 |
filter[title_cont] | string Filter by title contains, for example ?filter[title_cont]=favorite |
filter[type_eq] | string Filter by field type equals, for example ?filter[type_eq]=TextField |
filter[required_eq] | string Filter by required field equals, for example ?filter[required_eq]=true |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "title": "string",
- "handle": "string",
- "type": "string",
- "required": true
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
handle
(string) - The key for a contact
resource, e.g. custom_1
, custom_2
, custom_3
title
(string) - The title of the custom fieldtype
(string) - The type of the custom fieldrequired
(boolean) - Whether the custom field is requiredarchived
(boolean) - Whether the custom field is archivedUse the fields[custom_fields]
parameter to include only specific attributes:
GET /v1/custom_fields/123?fields[custom_fields]=handle,title
Response will include only the specified fields
{
"data": {
"id": "123",
"type": "custom_fields",
"attributes": {
"handle": "custom_1",
"title": "Favorite Song"
}
}
}
id required | string |
fields[custom_fields] | string Partial attributes as specified, e.g. fields[custom_fields]=title,handle |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "title": "string",
- "handle": "string",
- "type": "string",
- "required": true
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
List of customers
Use page[number]
and page[size]
parameters to paginate results:
GET /v1/customers?page[number]=1&page[size]=10
GET /v1/customers?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://app.kajabi.com/api/v1/customers?page[number]=2&page[size]=10",
"first": "https://app.kajabi.com/api/v1/customers?page[number]=1&page[size]=10",
"prev": "https://app.kajabi.com/api/v1/customers?page[number]=1&page[size]=10",
"next": "https://app.kajabi.com/api/v1/customers?page[number]=3&page[size]=10",
"last": "https://app.kajabi.com/api/v1/customers?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Sorting by created_at in ascending order (oldest first)
GET /v1/customers?filter[site_id]=123&sort=created_at
Use the sort
parameter to sort the results:
GET /v1/customers?filter[site_id]=123&sort=name
GET /v1/customers?filter[site_id]=123&sort=-email
GET /v1/customers?filter[site_id]=123&sort=net_revenue
GET /v1/customers?filter[site_id]=123&sort=-last_request_at
Response will include customers sorted by the specified field
{
"data": [{
"id": "123",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"external_user_id": "cust_123"
}
}]
}
Use the fields[customers]
parameter to request only specific attributes:
GET /v1/customers?fields[customers]=name,email
Response will only include requested fields
{
"data": [{
"id": "123",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]"
}
}]
}
Use the filter[site_id]
parameter to filter customers by site:
GET /v1/customers?filter[site_id]=123
Response will include only customers from the specified site
{
"data": [{
"id": "456",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"external_user_id": "cust_123"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the use_indexed_data
parameter along with filter[site_id]
and filter[search]
to search customers using an alternative search algorithm:
GET /v1/customers?filter[site_id]=123&filter[search]=smith&use_indexed_data=true
Response will include matching contacts using the indexed search algorithm
{
"data": [{
"id": "456",
"type": "customers",
"attributes": {
"name": "John Smith",
"email": "[email protected]"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
You can combine multiple filter parameters to refine your search:
GET /v1/customers?filter[site_id]=123&filter[search]=smith
Response will include only customers from the specified site matching the search term
{
"data": [{
"id": "456",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"external_user_id": "cust_123"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
You can filter customers by both site and offer ownership:
GET /v1/customers?filter[site_id]=123&filter[has_offer_id]=789
Response will include only customers from the specified site who have been granted the offer
{
"data": [{
"id": "456",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"external_user_id": "cust_123"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
},
"offers": {
"links": {
"self": "https://app.kajabi.com/api/v1/customers/456/relationships/offers",
"related": "https://app.kajabi.com/api/v1/customers/456/offers"
}
}
}
}]
}
You can filter customers by both site and product ownership:
GET /v1/customers?filter[site_id]=123&filter[has_product_id]=789
Response will include only customers from the specified site who have purchased the product
{
"data": [{
"id": "456",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"external_user_id": "cust_123"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
},
"offers": {
"links": {
"self": "https://app.kajabi.com/api/v1/customers/456/relationships/offers",
"related": "https://app.kajabi.com/api/v1/customers/456/offers"
}
}
}
}]
}
You can combine filtering, sparse fields, pagination and search in a single request:
GET /v1/customers?filter[site_id]=123&fields[customers]=name,email&page[number]=2&page[size]=10&filter[search]=smith
Response will include paginated, filtered customers with sparse fields
{
"data": [{
"id": "456",
"type": "customers",
"attributes": {
"name": "John Smith",
"email": "[email protected]"
}
}],
"links": {
"self": "https://app.kajabi.com/api/v1/customers?filter[site_id]=123&fields[customers]=name,email&page[number]=2&page[size]=10&filter[search]=smith",
"first": "https://app.kajabi.com/api/v1/customers?filter[site_id]=123&fields[customers]=name,email&page[number]=1&page[size]=10&filter[search]=smith",
"prev": "https://app.kajabi.com/api/v1/customers?filter[site_id]=123&fields[customers]=name,email&page[number]=1&page[size]=10&filter[search]=smith",
"next": null,
"last": "https://app.kajabi.com/api/v1/customers?filter[site_id]=123&fields[customers]=name,email&page[number]=2&page[size]=10&filter[search]=smith"
},
"meta": {
"total_pages": 2,
"total_count": 15,
"current_page": 2
}
}
sort | string Sort order, use: name, email, created_at, net_revenue, last_request_at for descending order use '-' e.g. &sort=-name |
page[number] | number |
page[size] | number Number of documents |
fields[customers] | string Sparse fields, use: name, email for example ?fields[customers]=name,email |
filter[site_id] | string Filter by site_id, for example ?filter[site_id]=111 |
filter[search] | string Filter with fuzzy search of name/email, for example ?filter[search]=alexa |
filter[has_offer_id] | string Filter based on granted offer, for example ?filter[has_offer_id]=111 |
filter[has_product_id] | string Filter based on product purchase, for example ?filter[has_product_id]=222 |
use_indexed_data | string Alternative algorithm for searching/filtering (in some cases performs faster), for example ?use_indexed_data=true |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "avatar": "string",
- "external_user_id": "string",
- "public_bio": "string",
- "public_location": "string",
- "public_website": "string",
- "socials": {
- "twitter": "string",
- "facebook": "string",
- "instagram": "string"
}, - "net_revenue": "string",
- "sign_in_count": 0,
- "last_request_at": "string",
- "bounced_at": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "contact": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offers": {
- "links": {
- "self": "string"
}
}, - "products": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}, - "links": {
- "contact": "string"
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
Show customer details
name
and email
attributes are kept in sync with the related contact
resourceexternal_user_id
attribute may be used as a customer reference in an external systemname
(string) - The customer's full name. This is a required field and can be either user-provided or auto-generated from their email address if left blank.email
(string) - The customer's email address. This is a required field and must be unique within a site. It's automatically downcased and stripped of whitespace. Used for authentication and communication.avatar
(string) - A URL to the customer's profile image. Can be either a custom uploaded avatar or falls back to Gravatar. If not set, defaults to a blank image.external_user_id
(string) - An optional external identifier that can be used to link the customer to external systems. Must be unique within a site.public_bio
(string) - A text field containing the customer's public biography or description. This is optional and can be displayed in community/social features.public_location
(string) - A text field for the customer's public location information. Optional field used for community/social features.public_website
(string) - The customer's website URL. This is validated to ensure it's a proper URL format and is transformed to ensure proper formatting.socials
(object) - A collection of the customer's social media links and profiles.net_revenue
(string) - The total revenue generated by this customer through their purchases. This is calculated from their successful payment transactions.sign_in_count
(integer) - A counter tracking how many times the customer has signed into their account.last_request_at
(string) - Timestamp of the customer's most recent activity or request. Used to track user engagement and activity.bounced_at
(string) - Timestamp indicating when the customer's email started bouncing. This is reset if the email address is changed.created_at
(string) - Timestamp when the customer record was created.updated_at
(string) - Timestamp when the customer record was last updated.Use the include
parameter to include related resources:
GET /v1/customers/123?include=contact,offers,products
Response will include related resources
{
"data": {
"id": "123",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"avatar": null,
"external_user_id": "cust_123",
"public_bio": null,
"public_location": null,
"public_website": null,
"socials": null,
"net_revenue": "0.0",
"sign_in_count": 0,
"last_request_at": null,
"bounced_at": null,
"created_at": "2021-01-01T00:00:00Z",
"updated_at": "2021-01-01T00:00:00Z"
},
"links": {
"contact": "https://app.kajabi.com/api/v1/contacts/321"
},
"relationships": {
"contact": {
"data": {
"id": "321",
"type": "contacts"
}
},
"offers": {
"data": [{ "id": "456", "type": "offers" }],
"links": {
"self": "https://app.kajabi.com/api/v1/customers/123/relationships/offers"
}
},
"products": {
"data": [{ "id": "789", "type": "products" }]
}
}
},
"included": [
{
"id": "456",
"type": "offers",
"attributes": {
"name": "Offer 1",
"description": "Offer 1 description",
"internal_title": "Offer 1",
"price_in_cents": 0,
"payment_type": "free",
"token": "offer_123",
"payment_method": "none",
"price_description": "Free",
"checkout_url": "https://mywebsite.com/offers/456",
"recurring_offer": false,
"subscription": false,
"one_time": true,
"single": false,
"free": true
}
},
{
"id": "789",
"type": "products",
"attributes": {
"created_at": "2024-11-12T23:43:09.551Z",
"title": "Course 1",
"description": "Course 1 description",
"status": "ready",
"members_aggregate_count": 0,
"product_type_name": "Course",
"product_type_id": 789,
"publish_status": "published",
"thumbnail_url": null
}
},
{
"id": "321",
"type": "contacts",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]",
"address_line_1": null,
"address_line_2": null,
"address_city": null,
"address_country": null,
"address_state": null,
"address_zip": null,
"phone_number": null,
"business_number": null,
"subscribed": false,
"external_user_id": null,
"created_at": "2024-11-20T18:53:19.389Z",
"updated_at": "2024-11-20T18:53:19.389Z"
}
}
]
}
Use the fields[customers]
parameter to request only specific attributes:
GET /v1/customers/123?fields[customers]=name,email
Response will only include requested fields
{
"data": {
"id": "123",
"type": "customers",
"attributes": {
"name": "Alice Smith",
"email": "[email protected]"
}
}
}
You can combine filtering, sparse fields, pagination and search in a single request:
GET /v1/customers/123?include=products&fields[customers]=name&fields[product]=title
Response will include related resources with sparse fields
{
"data": {
"id": "123",
"type": "customers",
"attributes": {
"name": "Alice Smith"
},
"relationships": {}
},
"included": [
{
"id": "789",
"type": "products",
"attributes": {
"title": "Course 1"
}
}
]
}
id required | string |
include | string with ?include=offers,products the response will include the related resources |
fields[customers] | string Partial attributes as specified, e.g. fields[customers]=name,email |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "avatar": "string",
- "external_user_id": "string",
- "public_bio": "string",
- "public_location": "string",
- "public_website": "string",
- "socials": {
- "twitter": "string",
- "facebook": "string",
- "instagram": "string"
}, - "net_revenue": "string",
- "sign_in_count": 0,
- "last_request_at": "string",
- "bounced_at": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "contact": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offers": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}, - "products": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}, - "links": {
- "contact": "string"
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
Get the customer's relationship to offers (granted).
Response is a list of resource identifiers
{
"data": [
{ "type": "offers", "id": "123" },
{ "type": "offers", "id": "456" }
]
}
The related tag resources are available using the GET api/v1/offers
endpoint.
The resource identifier includes the offer id and type.
Example URLs: /api/v1/offers/123
, /api/v1/offers/456
customer_id required | string |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
Create an offer grant for a customer.
In the request body inlcude offer resource identifier(s), id: OFFER_ID
, type: "offers"
.
{ "data": [{"type": "offers", "id": "123"}] }
customer_id required | string |
required | Array of objects (resource_identifiers) |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
Revoke offer grant(s) using a list of resource identifiers
In the request body inlcude offer resource identifier(s), id: OFFER_ID
, type: "offers"
.
{ "data": [{"type": "offers", "id": "123"}] }
customer_id required | string |
required | Array of objects (resource_identifiers) |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
Replace offer grants (grants and revokes offers to/from customer) using a list of resource identifiers
In the request body inlcude offer resource identifier(s), id: OFFER_ID
, type: "offers"
.
{ "data": [{"type": "offers", "id": "456"}, {"type": "offers", "id": "789"}] }
customer_id required | string |
required | Array of objects (resource_identifier) |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
Contact forms for a site
Use page[number]
and page[size]
parameters to paginate results:
GET /v1/forms?page[number]=1&page[size]=10
GET /v1/forms?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://api.kajabi.com/v1/forms?page[number]=2&page[size]=10",
"first": "https://api.kajabi.com/v1/forms?page[number]=1&page[size]=10",
"prev": "https://api.kajabi.com/v1/forms?page[number]=1&page[size]=10",
"next": "https://api.kajabi.com/v1/forms?page[number]=3&page[size]=10",
"last": "https://api.kajabi.com/v1/forms?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Use the sort
parameter to sort the results:
GET /v1/forms?sort=title
GET /v1/forms?sort=-title
Response will include forms sorted by the specified field
{
"data": [
{
"id": "123",
"type": "forms",
"attributes": {
"title": "Contact Form A",
"description": "General contact form"
}
},
{
"id": "456",
"type": "forms",
"attributes": {
"title": "Contact Form B",
"description": "Newsletter signup form"
}
}
]
}
Use the fields[forms]
parameter to request only specific attributes:
GET /v1/forms?fields[forms]=title,description
Response will only include requested fields
{
"data": [{
"id": "123",
"type": "forms",
"attributes": {
"title": "Contact Form A",
"description": "General contact form"
}
}]
}
Use the filter[site_id]
parameter to get forms for a specific site:
GET /v1/forms?filter[site_id]=123
Response will only include forms for that site
{
"data": [{
"id": "456",
"type": "forms",
"attributes": {
"title": "Contact Form A",
"description": "General contact form"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[title_cont]
parameter to find forms where the title contains specific text:
GET /v1/forms?filter[title_cont]=course
Response will include forms with matching titles
{
"data": [{
"id": "456",
"type": "forms",
"attributes": {
"title": "Course Registration Form",
"description": "Sign up form for online courses"
}
}]
}
You can combine pagination, sorting, sparse fields and filtering in a single request:
GET /v1/forms?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[forms]=title,description
Response will include paginated and filtered forms with sparse fields
{
"data": [
{
"id": "456",
"type": "forms",
"attributes": {
"title": "Newsletter Form",
"description": "Newsletter signup form"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
],
"links": {
"self": "https://api.kajabi.com/v1/forms?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[forms]=title,description",
"first": "https://api.kajabi.com/v1/forms?page[number]=1&page[size]=10&sort=-title&filter[site_id]=123&fields[forms]=title,description",
"prev": "https://api.kajabi.com/v1/forms?page[number]=1&page[size]=10&sort=-title&filter[site_id]=123&fields[forms]=title,description",
"next": null,
"last": "https://api.kajabi.com/v1/forms?page[number]=2&page[size]=10&sort=-title&filter[site_id]=123&fields[forms]=title,description"
},
"meta": {
"total_pages": 2,
"total_count": 15,
"current_page": 2
}
}
sort | string Sort order, use: title for descending order use '-' e.g. &sort=-title |
page[number] | integer |
page[size] | integer Number of documents |
fields[forms] | string Partial attributes as specified, e.g. fields[forms]=title |
filter[site_id] | string Filter by site_id, for example ?filter[site_id]=111 |
filter[title_cont] | string Filter by title contains, for example ?filter[title_cont]=course |
{- "data": [
- {
- "id": "string",
- "type": "forms",
- "attributes": {
- "title": "string",
- "default": true,
- "webhook_url": { },
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "fields": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}
}
]
}
Shows details of a form
Forms belong to a site and can be associated with:
title
(string) - A required field that represents the name or heading of the form. This is used to identify and display the form in the user interface. Forms must have a unique title within a site and can be searched and sorted by this attribute.default
(boolean) - A boolean flag indicating whether this is the default form for the site. Each site can have one default form, which is typically used when no specific form is specified. The default form can be accessed using the special ID "default" in API calls. When true, this form is considered the site's primary contact form.webhook_url
(string) - An optional URL where form submission data will be sent via webhook. This allows integration with external systems. The URL:created_at
(string) - Timestamp indicating when the form was created. This is automatically set when the form is first created.updated_at
(string) - Timestamp indicating when the form was last modified. This is automatically updated whenever the form is changed.Use the include
parameter to load related resources:
GET /v1/forms/123?include=fields,offer,contact_tags
Response will include the requested related resources
{
"data": {
"id": "123",
"type": "forms",
"attributes": {
"title": "Contact Form",
"default": false,
"webhook_url": null,
"created_at": "2025-02-27T01:03:09.179Z",
"updated_at": "2025-02-27T01:03:25.365Z"
},
"relationships": {
"fields": {
"data": [
{ "id": "456", "type": "fields" },
{ "id": "789", "type": "fields" }
]
},
"offer": {
"data": { "id": "123", "type": "offers" }
},
"contact_tags": {
"data": [
{ "id": "456", "type": "contact_tags" },
{ "id": "789", "type": "contact_tags" }
]
}
}
},
"included": [
{
"id": "456",
"type": "fields", "attributes": { "name": "Name" }
},
{
"id": "789",
"type": "fields", "attributes": { "name": "Email" }
},
{
"id": "123",
"type": "offers", "attributes": { "name": "Offer A" }
},
{
"id": "456",
"type": "contact_tags", "attributes": { "name": "Tag A" }
},
{
"id": "789",
"type": "contact_tags", "attributes": { "name": "Tag B" }
}
]
}
Fields are used in:
The system maintains default fields like name
, email
, etc. that cannot be removed
title
(string) - The display name or label of the field. This is a required attribute that represents how the field will be shown to users in forms and interfaces. Aside from default fields, custom fields can have user-defined titles.type
(string) - The type of field, which must be one of these predefined types:TextField
- Standard text inputPhoneField
- Phone number inputEmailField
- Email address inputTextAreaField
- Multi-line text inputCheckboxField
- Boolean checkboxSelectBoxField
- Dropdown selectRadioButtonsField
- Radio button groupCountryField
- Country selectorMobilePhoneField
- Mobile phone inputrequired
(boolean) - A boolean indicating whether the field must be filled out. For default fields, this is set in the configuration, while custom fields can be marked as required or optional.handle
(string) - A unique identifier for the field within a site.select_options
(string) - For fields that have choices (SelectBoxField
, RadioButtonsField
), this contains the available options. The options are stored as newline-separated values and must be unique within the field.editable
(boolean) - A boolean indicating whether the field can be modified. Default fields typically have this set to false, while custom fields can be editable.created_at
(string) - Timestamp when the field was created.updated_at
(string) - Timestamp when the field was last updated.Use the fields[forms]
parameter to request only specific attributes:
GET /v1/forms/123?fields[forms]=title,webhook_url
Response will only include requested fields
{
"data": [{
"id": "123",
"type": "forms",
"attributes": {
"title": "Contact Form A",
"webhook_url": "https://example.com/webhook"
}
}]
}
You can combine include and sparse fields in a single request:
GET /v1/forms/123?include=fields&fields[forms]=title,webhook_url&&fields[fields]=title
Response will include related fields with sparse fields
{
"data": {
"id": "123",
"type": "forms",
"attributes": {
"title": "Contact Form A",
"webhook_url": "https://example.com/webhook"
},
"relationships": {}
},
"included": [
{
"id": "456",
"type": "fields",
"attributes": {
"title": "Name"
}
},
{
"id": "789",
"type": "fields",
"attributes": {
"title": "Email"
}
}
]
}
id required | string |
include | string Load the related resources, for example ?include=fields,site,offer,contact_tags |
fields[forms] | string Partial attributes as specified, e.g. fields[forms]=title,webhook_url |
{- "data": {
- "id": "string",
- "type": "forms",
- "attributes": {
- "title": "string",
- "default": true,
- "webhook_url": { },
- "created_at": "string",
- "updated_at": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "fields": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}
}
}
name
and email
attributes are required.email
attribute must be a valid and deliverable email address.Example request body:
{
"data": {
"type": "form_submissions",
"attributes": {
"name": "John Doe",
"email": "[email protected]"
}
}
}
Response will include the newly created form submission resource.
{
"data": {
"id": "313",
"type": "form_submissions",
"attributes": {
"name": "John Doe",
"email": "[email protected]",
"address_line_1": null,
"address_line_2": null,
"address_city": null,
"address_country": null,
"address_state": null,
"address_zip": null,
"phone_number": null,
"business_number": null,
"mobile_phone_number": null
},
"relationships": {
"site": {
"data": {
"id": "2",
"type": "sites"
}
},
"form": {
"data": {
"id": "15",
"type": "forms"
}
}
}
}
}
id required | string |
required | object |
{- "data": {
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string"
}
}
}
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "name": "string",
- "email": "string",
- "phone_number": "string",
- "business_number": "string",
- "address_line_1": "string",
- "address_line_2": "string",
- "address_city": "string",
- "address_state": "string",
- "address_country": "string",
- "address_zip": "string",
- "custom_1": "string",
- "custom_2": "string",
- "custom_3": "string"
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "form": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
Returns the current user's profile data.
The response will include the following attributes:
initials
- A derived attribute that represents the user's initials based on their name. This is typically used for avatar placeholders or compact user displays. For example, "John Doe" would have initials "JD".name
- The user's full name. This is a required field that can be:email
- The user's email address. This is a critical field that:role_level
- Represents the user's permission level in the system. This attribute:{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "initials": "string",
- "name": "string",
- "email": "string",
- "role_level": "string"
}
}
}
List of offers (not archived) for a site that can be granted to a contact
Use page[number]
and page[size]
parameters to paginate results:
GET /v1/offers?page[number]=1&page[size]=10
GET /v1/offers?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://api.kajabi.com/v1/offers?page[number]=2&page[size]=10",
"first": "https://api.kajabi.com/v1/offers?page[number]=1&page[size]=10",
"prev": "https://api.kajabi.com/v1/offers?page[number]=1&page[size]=10",
"next": "https://api.kajabi.com/v1/offers?page[number]=3&page[size]=10",
"last": "https://api.kajabi.com/v1/offers?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Use the sort
parameter to sort the results:
GET /v1/offers?sort=title
GET /v1/offers?sort=-title
Response will include offers sorted by the specified field
{
"data": [
{
"id": "123",
"type": "offers",
"attributes": {
"title": "Advanced Course Bundle",
"price_in_cents": 19900,
"status": "active"
}
},
{
"id": "456",
"type": "offers",
"attributes": {
"title": "Beginner Course Bundle",
"price_in_cents": 9900,
"status": "active"
}
}
]
}
Use the fields[offers]
parameter to request only specific attributes:
GET /v1/offers?fields[offers]=title,price_in_cents
Response will only include requested fields
{
"data": [{
"id": "123",
"type": "offers",
"attributes": {
"title": "Advanced Course Bundle",
"price_in_cents": 19900
}
}]
}
Use the filter[site_id]
parameter to get offers for a specific site:
GET /v1/offers?filter[site_id]=123
Response will only include offers for that site
{
"data": [{
"id": "456",
"type": "offers",
"attributes": {
"title": "Advanced Course Bundle",
"price_in_cents": 19900,
"status": "active"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[title_cont]
parameter to find offers where the title contains specific text:
GET /v1/offers?filter[title_cont]=bundle
Response will include offers with matching titles
{
"data": [{
"id": "456",
"type": "offers",
"attributes": {
"title": "Advanced Course Bundle",
"price_in_cents": 19900,
"status": "active"
}
},
{
"id": "789",
"type": "offers",
"attributes": {
"title": "Basic Course Bundle",
"price_in_cents": 9900,
"status": "active"
}
}]
}
Use the filter[description_cont]
parameter to find offers where the description contains specific text:
GET /v1/offers?filter[description_cont]=marketing
Response will include offers with matching descriptions
{
"data": [{
"id": "456",
"type": "offers",
"attributes": {
"title": "Marketing Course Bundle",
"description": "Complete marketing course bundle with advanced strategies",
"price_in_cents": 19900,
"status": "active"
}
},
{
"id": "789",
"type": "offers",
"attributes": {
"title": "Business Essentials",
"description": "Business fundamentals including marketing and sales",
"price_in_cents": 9900,
"status": "active"
}
}]
}
Use the filter[price_description_eq]
parameter to find offers with a specific price description:
GET /v1/offers?filter[price_description_eq]=Free
Response will include offers with matching price description
{
"data": [{
"id": "456",
"type": "offers",
"attributes": {
"title": "Premium Course Bundle",
"price_in_cents": 0,
"price_description": "Free",
"status": "active"
}
},
{
"id": "789",
"type": "offers",
"attributes": {
"title": "Basic Course Bundle",
"price_in_cents": 0,
"price_description": "Free",
"status": "active"
}
}]
}
You can combine pagination, sorting, sparse fields and filtering in a single request:
GET /v1/offers?page[number]=2&page[size]=10&sort=-price_in_cents&filter[site_id]=123&fields[offers]=title,price_in_cents
Response will include paginated and filtered offers with sparse fields
{
"data": [
{
"id": "456",
"type": "offers",
"attributes": {
"title": "Basic Course Bundle",
"price_in_cents": 9900
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}
],
"links": {
"self": "https://api.kajabi.com/v1/offers?page[number]=2&page[size]=10&sort=-price_in_cents&filter[site_id]=123&fields[offers]=title,price_in_cents",
"first": "https://api.kajabi.com/v1/offers?page[number]=1&page[size]=10&sort=-price_in_cents&filter[site_id]=123&fields[offers]=title,price_in_cents",
"prev": "https://api.kajabi.com/v1/offers?page[number]=1&page[size]=10&sort=-price_in_cents&filter[site_id]=123&fields[offers]=title,price_in_cents",
"next": null,
"last": "https://api.kajabi.com/v1/offers?page[number]=2&page[size]=10&sort=-price_in_cents&filter[site_id]=123&fields[offers]=title,price_in_cents"
},
"meta": {
"total_pages": 2,
"total_count": 15,
"current_page": 2
}
}
sort | string Sort order, use: title, price_in_cents, for descending order use '-' e.g. &sort=-price_in_cents |
page[number] | number |
page[size] | number Number of documents |
fields[offers] | string Partial attributes as specified, e.g. fields[offers]=title,price_in_cents |
filter[site_id] | string Filter by site_id, for example ?filter[site_id]=111 |
filter[title_cont] | string Filter by title contains, for example ?filter[title_cont]=course |
filter[description_cont] | string Filter by description contains, for example ?filter[description_cont]=course |
filter[price_description_eq] | string Filter by exact price description, for example ?filter[price_description_eq]=Free |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "title": "string",
- "description": "string",
- "internal_title": "string",
- "currency": "string",
- "price_in_cents": 0,
- "payment_type": "string",
- "token": "string",
- "payment_method": "string",
- "price_description": "string",
- "checkout_url": "string",
- "recurring_offer": true,
- "subscription": true,
- "one_time": true,
- "single": true,
- "free": true
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "products": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
The offer system is a core part of Kajabi's e-commerce functionality, allowing course creators and digital product owners to monetize their content through various pricing and payment models while maintaining flexibility in how offers are presented and processed.
title
(string) - Required, public name of the offer shown to customersdescription
(string) - Optional, detailed information about what's included in the offerinternal_title
(string) - Optional, for internal reference/organization (not shown to customers)currency
(string) - The currency of the offer, defaults to USDprice_in_cents
(integer) - The USD price in cents (for precise decimal handling)payment_type
(string) - Indicates the payment structuretoken
(string) - A unique identifier for the offer, particularly in checkout URLspayment_method
(string) - Indicates the payment method, Returns empty string if no payment method is setprice_description
(string) - Human-readable representation of the offer's price, includes formatting and currency informationcheckout_url
(string) - Full URL where customers can purchase the offerrecurring_offer
(boolean) - Whether the offer has recurring paymentssubscription
(boolean) - Whether the offer is a subscription offerone_time
(boolean) - Whether the offer is a one-time offersingle
(boolean) - Whether the offer is a single offerfree
(boolean) - Whether the offer is a free offerUse the include
parameter to include related products:
GET /v1/offers/123?include=products
Response will include products relationship
{
"data": {
"id": "123",
"type": "offers",
"attributes": {
"title": "Advanced Course Bundle",
"description": "Complete advanced course bundle with expert guidance",
"internal_title": "advanced_course_bundle",
"currency": "USD",
"price_in_cents": 19900,
"payment_type": "stripe",
"token": "123",
"payment_method": "stripe",
"price_description": "$199.00",
"checkout_url": "https://api.kajabi.com/checkout/123",
"recurring_offer": false,
"subscription": false,
"one_time": true,
"single": true,
"free": false,
"thumbnail_url": "https://api.kajabi.com/images/456"
},
"relationships": {
"products": {
"data": [
{
"id": "456",
"type": "products"
}
]
}
}
},
"included": [
{
"id": "456",
"type": "products",
"attributes": {
"created_at": "2021-01-01T00:00:00Z",
"title": "Advanced Course",
"description": "Complete advanced course with expert guidance",
"status": "ready",
"members_aggregate_count": 100,
"product_type_name": "Course",
"product_type_id": 456,
"publish_status": "published",
"thumbnail_url": "https://api.kajabi.com/images/456"
}
}
]
}
GET /v1/offers/123?fields[offers]=title,price_in_cents
Response will only include requested fields
{
"data": {
"id": "123",
"type": "offers",
"attributes": {
"title": "Advanced Course Bundle",
"price_in_cents": 19900
}
}
}
You can combine include and sparse fields in a single request:
GET /v1/offers/123?include=products&fields[offers]=title,description&fields[products]=title,publish_status
Response will include offer and products with sparse fields
{
"data": {
"id": "123",
"type": "offers",
"attributes": {
"title": "Advanced Course Bundle",
"description": "Complete advanced course bundle with expert guidance"
},
"relationships": {}
},
"included": [
{
"id": "456",
"type": "products",
"attributes": {
"title": "Advanced Course",
"publish_status": "published"
}
}
]
}
id required | string |
include | string Load the related resources, for example ?include=products |
fields[offers] | string Partial attributes as specified, e.g. fields[offers]=title,price_in_cents |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "title": "string",
- "description": "string",
- "internal_title": "string",
- "currency": "string",
- "price_in_cents": 0,
- "payment_type": "string",
- "token": "string",
- "payment_method": "string",
- "price_description": "string",
- "checkout_url": "string",
- "recurring_offer": true,
- "subscription": true,
- "one_time": true,
- "single": true,
- "free": true
}, - "relationships": {
- "site": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "products": {
- "data": [
- {
- "id": "string",
- "type": "string"
}
]
}
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
get the offer's relationship to products, response is a list of resource identifiers
offer_id required | string |
{- "data": [
- {
- "id": "string",
- "type": "string"
}
], - "links": {
- "self": "string"
}
}
List of sites that the current user has access to
Use page[number]
and page[size]
parameters to paginate results:
GET /v1/sites?page[number]=1&page[size]=10
GET /v1/sites?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://api.kajabi.com/v1/sites?page[number]=2&page[size]=10",
"first": "https://api.kajabi.com/v1/sites?page[number]=1&page[size]=10",
"prev": "https://api.kajabi.com/v1/sites?page[number]=1&page[size]=10",
"next": "https://api.kajabi.com/v1/sites?page[number]=3&page[size]=10",
"last": "https://api.kajabi.com/v1/sites?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Use the sort
parameter to sort the results:
GET /v1/sites?sort=title
GET /v1/sites?sort=-title
Response will include sites sorted by the specified field
{
"data": [
{
"id": "123",
"type": "sites",
"attributes": {
"title": "Advanced Training Site",
"subdomain": "advanced-training"
}
},
{
"id": "456",
"type": "sites",
"attributes": {
"title": "Beginner Training Site",
"subdomain": "beginner-training"
}
}
]
}
Use the fields[sites]
parameter to request only specific attributes:
GET /v1/sites?fields[sites]=title,subdomain
Response will only include requested fields
{
"data": [{
"id": "123",
"type": "sites",
"attributes": {
"title": "Advanced Training Site",
"subdomain": "advanced-training"
}
}]
}
Use the filter[title_cont]
parameter to find sites where the title contains specific text:
GET /v1/sites?filter[title_cont]=training
Response will include sites with matching titles
{
"data": [{
"id": "123",
"type": "sites",
"attributes": {
"title": "Advanced Training Site",
"subdomain": "advanced-training"
}
},
{
"id": "456",
"type": "sites",
"attributes": {
"title": "Beginner Training Site",
"subdomain": "beginner-training"
}
}]
}
Use the filter[subdomain_cont]
parameter to find sites where the subdomain contains specific text:
GET /v1/sites?filter[subdomain_cont]=training
Response will include sites with matching subdomains
{
"data": [{
"id": "123",
"type": "sites",
"attributes": {
"title": "Advanced Training Site",
"subdomain": "advanced-training"
}
},
{
"id": "456",
"type": "sites",
"attributes": {
"title": "Beginner Training Site",
"subdomain": "beginner-training"
}
}]
}
You can combine pagination, sorting and sparse fields in a single request:
GET /v1/sites?page[number]=2&page[size]=10&sort=-title&fields[sites]=title,subdomain
Response will include paginated sites with sparse fields
{
"data": [
{
"id": "456",
"type": "sites",
"attributes": {
"title": "Beginner Training Site",
"subdomain": "beginner-training"
}
}
],
"links": {
"self": "https://api.kajabi.com/v1/sites?page[number]=2&page[size]=10&sort=-title&fields[sites]=title,subdomain",
"first": "https://api.kajabi.com/v1/sites?page[number]=1&page[size]=10&sort=-title&fields[sites]=title,subdomain",
"prev": "https://api.kajabi.com/v1/sites?page[number]=1&page[size]=10&sort=-title&fields[sites]=title,subdomain",
"next": null,
"last": "https://api.kajabi.com/v1/sites?page[number]=2&page[size]=10&sort=-title&fields[sites]=title,subdomain"
},
"meta": {
"total_pages": 2,
"total_count": 15,
"current_page": 2
}
}
sort | string Sort order, use: title, subdomain, for descending order use '-' e.g. &sort=-title |
page[number] | number |
page[size] | number Number of documents |
fields[sites] | string Partial attributes as specified, e.g. fields[sites]=title,subdomain |
filter[title_cont] | string Filter by title contains, for example ?filter[title_cont]=training |
filter[subdomain_cont] | string Filter by subdomain contains, for example ?filter[subdomain_cont]=training |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "title": "string",
- "subdomain": "string",
- "created_at": "string",
- "updated_at": "string"
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
The site system is a fundamental part of Kajabi's platform, representing a customer's branded presence and serving as the container for their products, courses, and other content. Each site can be customized extensively while maintaining the core functionality needed for e-learning and digital product delivery.
title
(string) - A required field that represents the name of the sitesubdomain
(string) - The subdomain of the site, used for routing and site identificationcreated_at
(string) - A read-only timestamp, ISO date string format, that indicates when the site was createdupdated_at
(string) - A read-only timestamp, ISO date string format, that indicates when the site was last modifiedUse the fields[sites]
parameter to request only specific attributes:
GET /v1/sites/123?fields[sites]=title,subdomain
Response will only include requested fields
{
"data": {
"id": "123",
"type": "sites",
"attributes": {
"title": "Advanced Training Site",
"subdomain": "advanced-training"
}
}
}
id required | string |
fields[sites] | string Partial attributes as specified, e.g. fields[sites]=title,subdomain |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "title": "string",
- "subdomain": "string",
- "created_at": "string",
- "updated_at": "string"
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
List of transactions
Use page[number]
and page[size]
parameters to paginate results:
GET /v1/transactions?page[number]=1&page[size]=10
GET /v1/transactions?page[number]=2&page[size]=25
The response includes pagination links and meta data:
{
"links": {
"self": "https://api.kajabi.com/v1/transactions?page[number]=2&page[size]=10",
"first": "https://api.kajabi.com/v1/transactions?page[number]=1&page[size]=10",
"prev": "https://api.kajabi.com/v1/transactions?page[number]=1&page[size]=10",
"next": "https://api.kajabi.com/v1/transactions?page[number]=3&page[size]=10",
"last": "https://api.kajabi.com/v1/transactions?page[number]=5&page[size]=10"
},
"meta": {
"total_pages": 5,
"total_count": 50,
"current_page": 2
}
}
Use the fields[transactions]
parameter to request only specific attributes:
GET /v1/transactions?fields[transactions]=amount_in_cents,sales_tax_in_cents
Response will only include requested fields
{
"data": [{
"id": "123",
"type": "transactions",
"attributes": {
"amount_in_cents": 9900,
"sales_tax_in_cents": 990
}
}]
}
Use the filter[site_id]
parameter to filter transactions by site:
GET /v1/transactions?filter[site_id]=123
Response will include only transactions for the specified site
{
"data": [{
"id": "456",
"type": "transactions",
"attributes": {
"amount_in_cents": 9900,
"sales_tax_in_cents": 990,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
Use the filter[start_date]
and filter[end_date]
parameters to filter transactions by date range:
GET /v1/transactions?filter[start_date]=2024-01-01&filter[end_date]=2024-01-31
Response will include only transactions within the specified date range
{
"data": [{
"id": "456",
"type": "transactions",
"attributes": {
"amount_in_cents": 9900,
"sales_tax_in_cents": 990,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}]
}
You can combine multiple parameters to filter and format the response:
GET /v1/transactions?page[number]=1&page[size]=10&fields[transactions]=amount_in_cents,sales_tax_in_cents&filter[site_id]=123&filter[start_date]=2024-01-01&filter[end_date]=2024-01-31
Response will include paginated transactions matching all filters, with only requested fields:
{
"data": [{
"id": "456",
"type": "transactions",
"attributes": {
"amount_in_cents": 9900,
"sales_tax_in_cents": 990
},
"relationships": {
"site": {
"data": {
"id": "123",
"type": "sites"
}
}
}
}],
"meta": {
"total_pages": 1,
"current_page": 1
}
}
page[number] | number |
page[size] | number Number of documents |
fields[transactions] | string Partial attributes as specified, e.g. fields[transactions]=amount_in_cents,sales_tax_in_cents |
filter[site_id] | string Filter by site_id, for example ?filter[site_id]=111 |
filter[start_date] | string Filter by start_date, for example ?filter[start_date]=2024-12-01 |
filter[end_date] | string Filter by end_date, for example ?filter[end_date]=2024-12-31 |
{- "data": [
- {
- "id": "string",
- "type": "string",
- "attributes": {
- "action": "string",
- "state": "string",
- "payment_type": "string",
- "amount_in_cents": 0,
- "sales_tax_in_cents": 0,
- "currency": "string",
- "currency_symbol": "string",
- "formatted_amount": "string",
- "created_at": "string"
}, - "relationships": {
- "customer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offer": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}
], - "links": {
- "self": "string",
- "current": "string"
}
}
The transaction system is a critical part of Kajabi's payment infrastructure, handling all monetary operations while maintaining detailed records for accounting, reporting, and compliance purposes.
action
(string) - Indicate the type of transaction:charge
- One-time paymentrefund
- Money returned to customersubscribe
- New subscriptionsubscription_charge
- Recurring subscription paymentfree_purchase
- $0 transactiontest
- Test transactiondispute
- Disputed chargesubscription_update
- Subscription modificationstate
(string) - The transaction's status:initialized
- Transaction startedsucceeded
- Transaction completed successfullyfailed
- Transaction failedpayment_type
(string) - Indicates the payment structure (nullable)amount_in_cents
(integer) - The USD price in cents (for precise decimal handling) can be negative for refundssales_tax_in_cents
(integer) - The USD sales tax in cents (for precise decimal handling)currency
(string) - String representing the currency code (nullable) automatically upcasedcurrency_symbol
(string) - String representing the currency symbol (nullable)formatted_amount
(string) - String representing the amount in a human-readable formatcreated_at
(string) - The creation date and time, ISO date string format (read-only) Use the fields[transactions]
parameter to request only specific attributes:
GET /v1/transactions/123?fields[transactions]=amount_in_cents,sales_tax_in_cents
Response will only include requested fields
{
"data": {
"id": "123",
"type": "transactions",
"attributes": {
"amount_in_cents": 9900,
"sales_tax_in_cents": 990
}
}
}
Use the include
parameter to include related resources:
GET /v1/transactions/123?include=customer,offer
Response will include related resources
{
"data": {
"id": "123",
"type": "transactions",
"attributes": {
"action": "subscription_charge",
"state": "succeeded",
"payment_type": "subscription",
"amount_in_cents": 100,
"sales_tax_in_cents": 0,
"currency": "USD",
"currency_symbol": "$",
"formatted_amount": "$1.00",
"created_at": "2025-03-14T19:17:38.000Z"
},
"relationships": {
"customer": {
"data": {
"id": "456",
"type": "customers"
}
},
"offer": {
"data": {
"id": "789",
"type": "offers"
}
}
}
},
"included": [
{
"id": "456",
"type": "customers",
"attributes": {
"name": "John Doe"
"email": "[email protected]",
"avatar": "https://example.com/avatar.jpg",
"external_user_id": "123",
"public_bio": "Public Bio",
"public_location": "Public Location",
"public_website": "https://example.com",
"socials": {
"twitter": "https://twitter.com",
"facebook": "https://facebook.com",
"linkedin": "https://linkedin.com"
},
"net_revenue": 10000,
"sign_in_count": 10,
"last_request_at": "2024-01-15T10:30:00Z",
"bounced_at": "2024-01-15T10:30:00Z",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
},
{
"id": "789",
"type": "offers",
"attributes": {
"title": "Offer Title",
"description": "Offer Description",
"internal_title": "Internal Title",
"price_in_cents": 9900,
"payment_type": "payment_method",
"token": "offer_token",
"payment_method": "payment_method",
"price_description": "Price Description",
"checkout_url": "https://example.com/checkout",
"recurring_offer": true,
"subscription": true,
"one_time": false,
"single": false,
"free": false
}
}
]
}
You can combine sparse fields and include in a single request:
GET /v1/transactions/123?include=customer&fields[transactions]=amount_in_cents,sales_tax_in_cents&fields[customers]=name,email
Response will include transaction with only requested fields and included customer with only name and email fields
{
"data": {
"id": "123",
"type": "transactions",
"attributes": {
"amount_in_cents": 9900,
"sales_tax_in_cents": 990
},
"relationships": {}
},
"included": [
{
"id": "456",
"type": "customers",
"attributes": {
"name": "John Doe"
"email": "[email protected]"
}
}
]
}
id required | string |
fields[transactions] | string Partial attributes as specified, e.g. fields[transactions]=amount_in_cents,sales_tax_in_cents |
include | string Load the related resources, for example ?include=customer,offer |
{- "data": {
- "id": "string",
- "type": "string",
- "attributes": {
- "action": "string",
- "state": "string",
- "payment_type": "string",
- "amount_in_cents": 0,
- "sales_tax_in_cents": 0,
- "currency": "string",
- "currency_symbol": "string",
- "formatted_amount": "string",
- "created_at": "string"
}, - "relationships": {
- "customer": {
- "data": {
- "id": "string",
- "type": "string"
}
}, - "offer": {
- "data": {
- "id": "string",
- "type": "string"
}
}
}
}, - "links": {
- "self": "string",
- "current": "string"
}
}
Returns the current version of the Kajabi API and links to the API documentation.
This endpoint does not require authentication; it can be used as a health check.
meta
(object) - Meta information about the API.title
(string) - The title of the API.version
(string) - The version of the API.links
(object) - Links to the API documentation.documentation
(string) - The URL to the API documentation.jsonapi
(object) - JSON API information.version
(string) - The version of the JSON API.specficiation
(string) - The URL to the JSON API specification.{- "meta": {
- "title": "string",
- "version": "string"
}, - "links": {
- "documentation": "string"
}, - "jsonapi": {
- "version": "string",
- "specficiation": "string"
}
}