--- openapi: 3.0.3 x-mint: mcp: enabled: true info: title: Kajabi API V1 version: 1.1.0 description: | ## Public API * Server URL `https://api.kajabi.com` * Endpoint paths are prefixed with `/v1` * Version endpoint `GET https://api.kajabi.com/v1/version` * See the [Developers Site](https://developers.kajabi.com) for documentation and examples. * Try the demo [Postman collection](https://www.postman.com/kajabi-apis/beta-public-api-demo/collection/fg4iyaz/kajabi-public-api-v1) ## API Keys * Your API `client_id` and `client_secret` are available on the [User API Keys](https://app.kajabi.com/admin/settings/security) section of the Kajabi Admin Portal. * Custom API Keys can be created with specific permissions. * Click the "Create User API Key" button, enter a name (e.g. "My project"), select the user and permissions, and click "Create". * For security purposes, you may "Delete" or "Rotate" the api credentials at any time; which will invalidate any access tokens granted with the credentials. ## Video Walkthroughs * [Capabilities](https://drive.google.com/file/d/1Puc9B2sSdA-RQb7YMxmUXg4FVoEXytoc/view?usp=sharing) * [Getting Started](https://drive.google.com/file/d/1hbGRShkxven_QMWvgYrerHKURbcZrnvJ/view?usp=sharing) * [Error Examples](https://drive.google.com/file/d/1i0wQK71I1jpaZVsxYwsn62gVj40S_E7Y/view?usp=sharing) * [External Contact Form](https://drive.google.com/file/d/1HqpULXvan5TOK3LvM7nILCuCkCaX0kFT/view?usp=sharing) contact: email: support@kajabi.com name: Support url: https://help.kajabi.com/hc/en-us/articles/4404549690523-How-to-Get-Help-From-Kajabi-Live-Agents license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html paths: "/v1/oauth/token": post: summary: Get access token tags: - Authentication description: | ## Request `access_token` and `refresh_token` There are three ways to exchange parameters for tokens 1. Provide client credentials `client_id` and `client_secret` 2. Provide a `refresh_token` 3. Provide `username` and `password` (client credentials is preferred) ### Using grant_type=client_credentials Only include params: `client_id`, `client_secret`, and `grant_type`. * The `grant_type` param value must be: `client_credentials` ### Using grant_type=refresh_token Only include params: `refresh_token` and `grant_type`. * The `grant_type` param value must be: `refresh_token` * The `refresh_token` must be a unexpired JWT token, from a prior client credential token grant. ### Using username and password Only include params: `username` and `password`. ## Response A successful response will provide `access_token` and `refresh_token` values. * Use the `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` * Store the `refresh_token` to exchange for a new `access_token` when it expires. * Tokens may be invalidated using the `v1/oauth/revoke` endpoint to "log out". ### Attributes * `access_token` (string) - The access token for the API session * `refresh_token` (string) - The refresh token for the API session * `token_type` (string) - The type of token, always `Bearer` * `expires_in` (integer) - The number of seconds the access token will be valid for parameters: [] responses: '200': description: Authentication succeeded content: application/json: schema: "$ref": "#/components/schemas/oauth_token_response" '400': description: Bad Request content: application/json: schema: "$ref": "#/components/schemas/errors_authentication_failed" '401': description: Unauthorized content: application/json: schema: "$ref": "#/components/schemas/errors_authentication_failed" requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: username: type: string password: type: string client_id: type: string client_secret: type: string grant_type: type: string scope: type: string refresh_token: type: string "/v1/oauth/revoke": post: summary: Revoke a token tags: - Authentication description: | ## Revoke an `access_token` and `refresh_token` Either token may be provided to "log out" of the API session. Both tokens we be invalidated. * Only include param: `token` with your `access_token` or `refresh_token` * Requires an `Authorization` header as `Bearer access_token` to authenticate the request. ## Response * A successful response will have an empty body * An error response will include a JSON body with error details. security: - Bearer: [] parameters: [] responses: '200': description: Token revocation succeeded '401': description: Unauthorized requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: token: type: string required: - token "/v1/blog_posts": get: summary: List blog posts description: | Returns a list of blog posts which the current user may access ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/blog_posts[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/blog_posts[number]=2&page[size]=25` ## Sparse Fields Use the `fields[blog_posts]` parameter to request only specific attributes: ### Only return title attribute * `GET /v1/blog_posts?fields[blog_posts]=title` ## Sorting Use the `sort` parameter to sort the results: ### Sort by published_at in descending order * `GET /v1/blog_posts?sort=-published_at&fields[blog_posts]=title` ## Filters Use the `filter[site_id]` parameter to get blog posts for a specific site: ### Get blog posts for site with ID 123 * `GET /v1/blog_posts?filter[site_id]=123` List of attributes that may be used to filter: title, content, slug, page_title, page_description, published_at, created_at, updated_at, image_url, image_alt_text, tags The filter param uses the following syntax: `filter[attribute_name_suffix]` with suffix for comparison: * `eq` for equals * `cont` for contains * `not_eq` for not equals * `not_cont` for not contains * `start` for starts with * `end` for ends with For example: * `GET /v1/blog_posts?filter[title_start]=Announcing` * `GET /v1/blog_posts?filter[title_cont]=Announcing` tags: - Blog posts security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title for descending order use ''-'' e.g. &sort=-title' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: fields[blog_posts] in: query required: false description: Partial attributes as specified, e.g. fields[blog_posts]=title schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=hello schema: type: string responses: '200': description: Success, list of blog posts which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/blog_posts_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/blog_posts/{id}": get: summary: Blog post details description: | Shows details of a blog post ## Blog Post Attributes * `title` (string) - Title of the blog post * `url` (string) - URL of the blog post * `content` (string) - Content of the blog post * `slug` (string) - Slug of the blog post * `page_title` (string) - Page title of the blog post * `page_description` (string) - Page description of the blog post * `published_at` (string) - Date and time the blog post was published * `created_at` (string) - Date and time the blog post was created * `updated_at` (string) - Date and time the blog post was updated_at * `image_url` (string) - URL of the image associated with the blog post * `image_alt_text` (string) - Alt text for the image associated with the blog post * `tags` (array) - Tags associated with the blog post ## Sparse Fields ### Only return title attribute * `GET /v1/blog_posts/123?fields[blog_posts]=title` Response will only include requested fields ```json { "data": { "id": "123", "type": "blog_posts", "attributes": { "title": "Announcing New Course" } } } ``` tags: - Blog posts security: - Bearer: [] parameters: - name: id in: path required: true description: BlogPost ID schema: type: string - name: fields[blog_posts] in: query required: false description: Partial attributes as specified, e.g. fields[blog_posts]=title schema: type: string responses: '200': description: Success, shows details of a blog post content: application/vnd.api+json: schema: "$ref": "#/components/schemas/blog_posts_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/contact_notes": get: summary: List contact notes tags: - Contact Notes security: - Bearer: [] description: | Returns a paginated list of contact notes. This endpoint supports filtering, sorting, and pagination. **Sorting:** - `created_at` (default: descending) **Filtering:** - `filter[contact_id]` - Filter notes for a specific Contact - `filter[site_id]` - Filter notes for a specific Site **Pagination:** - Use `page[number]` and `page[size]` parameters - Default page size is 20, maximum is 100 parameters: - name: filter[contact_id] in: query required: false description: Filter contact notes for a specific contact by ID schema: type: string - name: filter[site_id] in: query required: false description: Filter contact notes for a specific site by ID schema: type: string - name: sort in: query required: false description: 'Sort field. Prefix with ''-'' for descending order. Available: created_at, updated_at' schema: type: string - name: page[number] in: query required: false description: Page number for pagination schema: type: integer - name: page[size] in: query required: false description: Number of items per page (max 100) schema: type: integer responses: '200': description: Contact notes filtered by contact_id content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_notes_index_response" '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" post: summary: Create contact note tags: - Contact Notes security: - Bearer: [] description: | Creates a new contact note. **Required Attributes:** - `body` (string) - The note content **Required Relationships:** - `contact` - The contact this note belongs to (resource identifier) parameters: [] responses: '201': description: Contact note created successfully content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_notes_show_response" '422': description: Invalid contact note data content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unprocessable" '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" requestBody: content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_notes_create_request" "/v1/contact_notes/{id}": parameters: - name: id in: path required: true schema: type: string get: summary: Contact note details description: | Returns a single contact note by ID. **Attributes:** - `body` (string) - The note content - `created_at` (datetime) - When the note was created - `updated_at` (datetime) - When the note was last modified **Relationships:** - `contact` - The contact this note belongs to tags: - Contact Notes security: - Bearer: [] parameters: - name: include in: query required: false description: with ?include=contact the response will include the related contact resource schema: type: string - name: fields[contact_notes] in: query required: false description: 'Sparse fields, use: body for example ?fields[contact_notes]=body' schema: type: string responses: '200': description: Contact note retrieved successfully content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_notes_show_response" '404': description: Contact note not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" patch: summary: Update contact note tags: - Contact Notes security: - Bearer: [] description: | Updates an existing contact note. Only the note body can be updated. **Updatable Attributes:** - `body` (string) - The note content Contact relationship cannot be changed after creation. parameters: [] responses: '200': description: Contact note updated successfully content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_notes_show_response" '422': description: Invalid contact note data content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unprocessable" '404': description: Contact note not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" requestBody: content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_notes_update_request" delete: summary: Delete contact note tags: - Contact Notes security: - Bearer: [] description: 'Deletes a contact note by ID. This action is permanent and cannot be undone. ' responses: '200': description: Contact note deleted successfully '404': description: Contact note not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" "/v1/contact_tags": get: summary: List contact tags description: | Tags (not archived) for a site ## Contact Tag Attributes * `name` (string) - The name of the contact tag ## Pagination Use the `page[number]` and `page[size]` query parameters to paginate results: ### Get first page of 10 items * `GET /v1/contact_tags?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/contact_tags?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/contact_tags?page[number]=2&page[size]=10", "first": "https://api.kajabi.com/v1/contact_tags?page[number]=1&page[size]=10", "prev": "https://api.kajabi.com/v1/contact_tags?page[number]=1&page[size]=10", "next": "https://api.kajabi.com/v1/contact_tags?page[number]=3&page[size]=10", "last": "https://api.kajabi.com/v1/contact_tags?page[number]=5&page[size]=10" }, "meta": { "total_pages": 5, "total_count": 50, "current_page": 2 } } ``` ## Filter by Site ID Use the `filter[site_id]` parameter to get contact tags for a specific site: ### Get contact tags for site with ID 123 * `GET /v1/contact_tags?filter[site_id]=123` Response will only include contact tags for that site ```json { "data": [{ "id": "456", "type": "contact_tags", "attributes": { "name": "Source" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Filter by Name Contains Use the `filter[name_cont]` parameter to find contact tags where the name contains specific text: ### Get contact tags with names containing "vip" * `GET /v1/contact_tags?filter[name_cont]=vip` Response will include contact tags with matching names ```json { "data": [{ "id": "456", "type": "contact_tags", "attributes": { "name": "VIP Customer" } }] } ``` ## Using Multiple Parameters Together You can combine pagination, sorting, sparse fields and filtering in a single request: ### Get page 2 of contact tags for site 123, sorted by name descending * `GET /v1/contact_tags?page[number]=2&page[size]=10&sort=-name&filter[site_id]=123` Response will include only requested fields, sorted and paginated ```json { "data": [{ "id": "456", "type": "contact_tags", "attributes": { "name": "Webinar Attendee" } }, { "id": "789", "type": "contact_tags", "attributes": { "name": "VIP Customer" } }], "links": { "self": "https://api.kajabi.com/v1/contact_tags?page[number]=2&page[size]=10&sort=-name&fields[contact_tags]=name,handle&filter[site_id]=123", "first": "https://api.kajabi.com/v1/contact_tags?page[number]=1&page[size]=10&sort=-name&fields[contact_tags]=name,handle&filter[site_id]=123", "prev": "https://api.kajabi.com/v1/contact_tags?page[number]=1&page[size]=10&sort=-name&fields[contact_tags]=name,handle&filter[site_id]=123", "next": "https://api.kajabi.com/v1/contact_tags?page[number]=3&page[size]=10&sort=-name&fields[contact_tags]=name,handle&filter[site_id]=123", "last": "https://api.kajabi.com/v1/contact_tags?page[number]=5&page[size]=10&sort=-name&fields[contact_tags]=name,handle&filter[site_id]=123" }, "meta": { "total_pages": 5, "total_count": 50, "current_page": 2 } } ``` tags: - Contact Tags security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: name, email, for descending order use ''-'' e.g. &sort=-name' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[contact_tags] in: query required: false description: Partial attributes as specified, e.g. fields[contact_tags]=name schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[name_cont] in: query required: false description: Filter by name contains, for example ?filter[name_cont]=vip schema: type: string responses: '200': description: Success, list of contact tags which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_tags_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/contact_tags/{id}": get: summary: Contact tag details description: | ## Contact Tag Attributes * `name` (string) - The name of the contact tag ## Contact Tag Relationships The contact tag belongs to a site tags: - Contact Tags security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string responses: '200': description: Success, shows details of a contact tag content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contact_tags_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/contacts": post: summary: Create a contact description: | Create a contact for a site. ## Contact attributes * New contact does not support `external_user_id` attribute. * See custom_fields endpoint to discover attributes for using custom fields attributes. ## Create a contact Request body must include a `site` relationship. Example request body: ```json { "data": { "type": "contacts", "attributes": { "name": "John Doe", "email": "john.doe@example.com" }, "relationships": { "site": { "data": { "type": "sites", "id": "123" } } } } } ``` Response will include the newly created contact resource. ```json { "data": { "id": "456", "type": "contacts", "attributes": { "name": "John Doe", "email": "john.doe@example.com", "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" } } } } } ``` tags: - Contacts security: - Bearer: [] parameters: [] responses: '201': description: Success, new contact created content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '400': description: Bad request, Site relationship is required content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '422': description: Unprocessable entity, attributes have semantic errors content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unprocessable" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: object properties: type: type: string attributes: "$ref": "#/components/schemas/contacts_attributes" relationships: type: object properties: site: type: object properties: data: type: object properties: id: type: string type: type: string required: - id - type required: - type - attributes - relationships required: - data get: summary: List contacts description: | List of contacts, we recommended filtering by site. ## Filtering Use the `filter[site_id]` parameter to filter contacts by site: ### Get contacts for site with ID 123 * `GET /v1/contacts?filter[site_id]=123` Response will include only contacts for the specified site ```json { "data": [{ "id": "456", "type": "contacts", "attributes": { "name": "John Smith", "email": "john@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Search Filter Use the `filter[search]` parameter along with `filter[site_id]` to search contacts by name or email: ### Search for contacts containing "smith" in site with ID 123 * `GET /v1/contacts?filter[site_id]=123&filter[search]=smith` Response will include only matching contacts for the specified site ```json { "data": [{ "id": "456", "type": "contacts", "attributes": { "name": "John Smith", "email": "smith.john@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Search Use the `filter[search]` parameter along with `filter[site_id]` to search contacts. ### Search for contacts containing "smith" in site with ID 123 * `GET /v1/contacts?filter[site_id]=123&filter[search]=smith` Response will include matching contacts ```json { "data": [{ "id": "456", "type": "contacts", "attributes": { "name": "John Smith", "email": "smith.john@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Using Pagination with Site Filter Use the `filter[site_id]` parameter along with pagination parameters `page[number]` and `page[size]` to get paginated results for a specific site: ### Get page 2 of contacts from site with ID 123, with 10 items per page * `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 ```json { "data": [{ "id": "456", "type": "contacts", "attributes": { "name": "John Smith", "email": "smith.john@example.com", "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 } } ``` ## Using Sort with Site Filter * The default Sorting is by created_at in descending order (newest first) 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 contacts from site with ID 123, sorted by name in ascending order * `GET /v1/contacts?filter[site_id]=123&sort=name` ### Get contacts from site with ID 123, sorted by email in descending order * `GET /v1/contacts?filter[site_id]=123&sort=-email` Response will include sorted contacts for the specified site ```json { "data": [{ "id": "456", "type": "contacts", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Using Sparse Fields with Site Filter Use the `fields[contacts]` parameter along with `filter[site_id]` to get specific fields for contacts in a site: ### Get only name and email fields for contacts from site with ID 123 * `GET /v1/contacts?filter[site_id]=123&fields[contacts]=name,email` Response will include only requested fields for contacts in the specified site ```json { "data": [{ "id": "456", "type": "contacts", "attributes": { "name": "Alice Smith", "email": "alice@example.com" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Filtering by Site and Offer Use the `filter[site_id]` parameter along with `filter[has_offer_id]` to get contacts who have been granted a specific offer ### Get contacts from site with ID 123 who have been granted offer with ID 789 * `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 ```json { "data": [{ "id": "456", "type": "contacts", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Filtering by Site and Tag Use the `filter[site_id]` parameter along with `filter[has_tag_id]` to get contacts who have a specific tag ### Get contacts from site with ID 123 who have tag with ID 456 * `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 ```json { "data": [{ "id": "789", "type": "contacts", "attributes": { "name": "Bob Jones", "email": "bob@example.com", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Using Multiple Parameters Together You can combine multiple parameters to filter, search, paginate and format the response: ### Get paginated contacts from site 123 with tag 456, searching for "smith", using indexed data and sparse fields * `GET /v1/contacts?filter[site_id]=123&filter[has_tag_id]=456&filter[search]=smith&=true&page[number]=1&page[size]=10&fields[contacts]=name,email` Response will include paginated contacts matching all filters with only requested fields ```json { "data": [{ "id": "789", "type": "contacts", "attributes": { "name": "John Smith", "email": "smith.john@example.com" } }], "links": { "self": "https://api.kajabi.com/v1/contacts?filter[site_id]=123&filter[has_tag_id]=456&filter[search]=smith&=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&=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&=true&page[number]=1&page[size]=10&fields[contacts]=name,email" }, "meta": { "total_pages": 1, "total_count": 1, "current_page": 1 } } ``` tags: - Contacts security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: name, email, created_at, for descending order use ''-'' e.g. &sort=-name' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[contacts] in: query required: false description: 'Sparse fields, use: name, email for example ?fields[contacts]=name,email' schema: type: string - name: filter[site_id] in: query required: false description: It is recommended to always filter by site_id, for example ?filter[site_id]=111. This param is required when the account has multiple sites schema: type: string - name: filter[search] in: query required: false description: Filter with fuzzy search of name/email, for example ?filter[search]=alexa schema: type: string - name: filter[created_in_last] in: query required: false description: Filter contacts created in the last N days, e.g. ?filter[created_in_last]=30 schema: type: string - name: filter[not_created_in_last] in: query required: false description: Filter contacts not created in the last N days schema: type: string - name: filter[is_hidden] in: query required: false description: Filter hidden contacts schema: type: string - name: filter[joined_in_last] in: query required: false description: Filter contacts who joined in the last N days schema: type: string - name: filter[active_in_last] in: query required: false description: Filter contacts active in the last N days schema: type: string - name: filter[inactive_in_last] in: query required: false description: Filter contacts inactive in the last N days schema: type: string - name: filter[name_contains] in: query required: false description: Filter contacts whose name contains the given value schema: type: string - name: filter[email_contains] in: query required: false description: Filter contacts whose email contains the given value schema: type: string - name: filter[phone_number_contains] in: query required: false description: Filter contacts whose phone number contains the given value schema: type: string - name: filter[address_line_1_contains] in: query required: false description: Filter contacts whose address line 1 contains the given value schema: type: string - name: filter[address_line_2_contains] in: query required: false description: Filter contacts whose address line 2 contains the given value schema: type: string - name: filter[address_city_contains] in: query required: false description: Filter contacts whose city contains the given value schema: type: string - name: filter[address_state_contains] in: query required: false description: Filter contacts whose state contains the given value schema: type: string - name: filter[address_country_contains] in: query required: false description: Filter contacts whose country contains the given value schema: type: string - name: filter[address_zip_contains] in: query required: false description: Filter contacts whose zip code contains the given value schema: type: string - name: filter[has_tag_id] in: query required: false description: Filter contacts with a specific tag ID schema: type: string - name: filter[has_all_tag_id] in: query required: false description: Filter contacts with all specified tag IDs schema: type: string - name: filter[has_no_tag_id] in: query required: false description: Filter contacts without the specified tag ID schema: type: string - name: filter[subscribed] in: query required: false description: Filter subscribed contacts schema: type: string - name: filter[has_offer_id] in: query required: false description: Filter contacts with a specific offer ID schema: type: string - name: filter[has_no_offer_id] in: query required: false description: Filter contacts without the specified offer ID schema: type: string - name: filter[has_product_id] in: query required: false description: Filter contacts who own a specific product ID schema: type: string - name: filter[has_active_product_id] in: query required: false description: Filter contacts with an active membership to a specific product ID schema: type: string - name: filter[has_no_product_id] in: query required: false description: Filter contacts who do not own a specific product ID schema: type: string - name: filter[previously_owned_product_id] in: query required: false description: Filter contacts who previously owned a specific product ID schema: type: string - name: filter[used_coupon_code] in: query required: false description: Filter contacts who used a specific coupon code schema: type: string - name: filter[submitted_form_id] in: query required: false description: Filter contacts who submitted a specific form ID schema: type: string - name: filter[no_submitted_form_id] in: query required: false description: Filter contacts who have not submitted the specified form ID schema: type: string - name: filter[registered_event_id] in: query required: false description: Filter contacts who registered for a specific event ID schema: type: string - name: filter[not_registered_event_id] in: query required: false description: Filter contacts who have not registered for the specified event ID schema: type: string - name: filter[completed_assessment_id] in: query required: false description: Filter contacts who completed a specific assessment ID schema: type: string - name: filter[passed_assessment_id] in: query required: false description: Filter contacts who passed a specific assessment ID schema: type: string - name: filter[failed_assessment_id] in: query required: false description: Filter contacts who failed a specific assessment ID schema: type: string - name: filter[net_revenue_equal_to] in: query required: false description: Filter contacts whose net revenue equals the given value schema: type: string - name: filter[net_revenue_greater_than] in: query required: false description: Filter contacts whose net revenue is greater than the given value schema: type: string - name: filter[net_revenue_less_than] in: query required: false description: Filter contacts whose net revenue is less than the given value schema: type: string - name: filter[subscribed_in_last] in: query required: false description: Filter contacts subscribed in the last N days schema: type: string - name: filter[unsubscribed_in_last] in: query required: false description: Filter contacts unsubscribed in the last N days schema: type: string - name: filter[never_subscribed] in: query required: false description: Filter contacts who have never subscribed schema: type: string - name: filter[sent_email_broadcast_id] in: query required: false description: Filter contacts who were sent a specific email broadcast ID schema: type: string - name: filter[no_sent_email_broadcast_id] in: query required: false description: Filter contacts who were not sent the specified email broadcast ID schema: type: string - name: filter[no_sent_email_broadcast_ids] in: query required: false description: Filter contacts who were not sent any of the specified email broadcast IDs schema: type: string - name: filter[no_delivered_email_broadcast_id] in: query required: false description: Filter contacts who did not receive the specified email broadcast ID schema: type: string - name: filter[opened_email_broadcast_id] in: query required: false description: Filter contacts who opened a specific email broadcast ID schema: type: string - name: filter[no_opened_email_broadcast_id] in: query required: false description: Filter contacts who did not open the specified email broadcast ID schema: type: string - name: filter[clicked_email_broadcast_id] in: query required: false description: Filter contacts who clicked a specific email broadcast ID schema: type: string - name: filter[no_clicked_email_broadcast_id] in: query required: false description: Filter contacts who did not click the specified email broadcast ID schema: type: string - name: filter[bounced_email_broadcast_id] in: query required: false description: Filter contacts who bounced a specific email broadcast ID schema: type: string - name: filter[no_bounced_email_broadcast_id] in: query required: false description: Filter contacts who did not bounce the specified email broadcast ID schema: type: string - name: filter[dropped_email_broadcast_id] in: query required: false description: Filter contacts who dropped a specific email broadcast ID schema: type: string - name: filter[no_dropped_email_broadcast_id] in: query required: false description: Filter contacts who did not drop the specified email broadcast ID schema: type: string - name: filter[opened_email_in_last] in: query required: false description: Filter contacts who opened an email in the last N days schema: type: string - name: filter[not_opened_email_in_last] in: query required: false description: Filter contacts who did not open an email in the last N days schema: type: string - name: filter[delivered_email_in_last] in: query required: false description: Filter contacts who were delivered an email in the last N days schema: type: string - name: filter[not_delivered_email_in_last] in: query required: false description: Filter contacts who were not delivered an email in the last N days schema: type: string - name: filter[clicked_email_in_last] in: query required: false description: Filter contacts who clicked an email in the last N days schema: type: string - name: filter[not_clicked_email_in_last] in: query required: false description: Filter contacts who did not click an email in the last N days schema: type: string - name: filter[is_hard_bouncing] in: query required: false description: Filter contacts that are hard bouncing schema: type: string - name: filter[bounced_in_last] in: query required: false description: Filter contacts who bounced in the last N days schema: type: string - name: filter[complained_in_last] in: query required: false description: Filter contacts who complained in the last N days schema: type: string - name: filter[manually_unsubscribed_in_last] in: query required: false description: Filter contacts manually unsubscribed in the last N days schema: type: string - name: filter[opted_out_in_last] in: query required: false description: Filter contacts who opted out in the last N days schema: type: string - name: filter[healthy_contacts_with_open_data] in: query required: false description: Filter healthy contacts with open data schema: type: string - name: filter[passive_contacts_with_open_data] in: query required: false description: Filter passive contacts with open data schema: type: string - name: filter[unengaged_contacts_with_open_data] in: query required: false description: Filter unengaged contacts with open data schema: type: string - name: filter[inactive_contacts_with_open_data] in: query required: false description: Filter inactive contacts with open data schema: type: string - name: filter[subscribed_newsletter_id] in: query required: false description: Filter contacts subscribed to a specific newsletter ID schema: type: string - name: filter[unsubscribed_newsletter_id] in: query required: false description: Filter contacts unsubscribed from a specific newsletter ID schema: type: string - name: filter[mobile_phone_number_contains] in: query required: false description: Filter contacts whose mobile phone number contains the given value schema: type: string - name: filter[subscribed_email_sequence_id] in: query required: false description: Filter contacts subscribed to a specific email sequence ID schema: type: string - name: filter[not_subscribed_email_sequence_id] in: query required: false description: Filter contacts not subscribed to a specific email sequence ID schema: type: string responses: '200': description: Success, list search results content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/contacts/{id}": get: summary: Contact details description: | Show details for a contact ## Contact Attributes * `name` (string) - The name of the contact * `email` (string) - The email of the contact, must be a valid and deliverable email address * `address_line_1` (string) - The first line of the contact's address * `address_line_2` (string) - The second line of the contact's address * `address_city` (string) - The city of the contact's address * `address_country` (string) - The country of the contact's address * `address_state` (string) - The state of the contact's address * `address_zip` (string) - The zip code of the contact's address * `phone_number` (string) - The phone number of the contact * `business_number` (string) - The business phone number of the contact * `subscribed` (boolean) - Whether the contact has opted in to receive marketing communications from the site * `external_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 purchase * `created_at` (string) - The date and time the contact was created * `updated_at` (string) - The date and time the contact was last updated ## Including Relationships Use 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 ```json { "data": { "id": "123", "type": "contacts", "attributes": { "name": "John Smith", "email": "john@example.com", "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": "john@example.com", "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" } } ] } ``` ## Sparse Fields 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 ```json { "data": { "id": "123", "type": "contacts", "attributes": { "name": "John Smith", "email": "john@example.com" } } } ``` ## Using Multiple Parameters Together 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 ```json { "data": { "id": "123", "type": "contacts", "attributes": { "email": "sam@example.com" }, "relationships": {} }, "included": [ { "id": "321", "type": "customers", "attributes": { "net_revenue": "0.0" } } ] } ``` tags: - Contacts security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: with ?include=offers,tags,customer the response will include the related contact offers, tags and customer resources schema: type: string - name: fields[contacts] in: query required: false description: 'Sparse fields, use: name, email for example ?fields[contacts]=name,email' schema: type: string responses: '200': description: Success, shows details for specified contact and tags relationship content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" patch: summary: Update contact description: | ## Contact attributes * A contact with a related customer resource does support `external_user_id` attribute. * See custom_fields endpoint to discover attributes for using custom fields attributes. ## Update a contact Example request body: ```json { "data": { "type": "contacts", "id": "456", "attributes": { "phone_number": "12134567890" } } } ``` Response will include the update contact resource. ```json { "data": { "id": "456", "type": "contacts", "attributes": { "name": "John Doe", "email": "john.doe@example.com", "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" } } } } } ``` tags: - Contacts security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string responses: '200': description: Success, contact updated content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '422': description: Unprocessable entity, attributes have semantic errors content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unprocessable" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/contacts_attributes" required: - id - type - attributes relationships: type: object properties: tags: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" required: - data delete: summary: Delete contact tags: - Contacts security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string responses: '200': description: Success, destroys the contact content: application/vnd.api+json: schema: "$ref": "#/components/schemas/empty_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '422': description: Unprocessable entity, contact has active Kajabi Payments subscriptions content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unprocessable" "/v1/contacts/{contact_id}/relationships/offers": get: summary: List contact's offers description: | Get the contact's relationship to offers (granted). Response is a list of resource identifiers ```json { "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` tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, shows details for tags relationship content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" post: summary: Grant offer to contact description: |+ ## Grant offer(s) to a contact 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.) ## Response * A successful response body will list the offers related to the contact * An error response will include a JSON body with error details. ## Behaviors and side effects * Checks if the contact was already granted the offer * Checks for existing customerby email * If no existing customer, generates a new customer record with contact details * May send a welcome email to the customer * May send a gift granted email if this is a gift offer * Triggers automations if configured tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, adds tag relationship to contact resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" meta: type: object properties: send_customer_welcome_email: type: boolean required: - data delete: summary: Revoke offer from contact description: | ## Revoke offer grant(s) for a contact 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"}] } ``` ## Response * A successful response body will list the offers related to the contact * An error response will include a JSON body with error details. ## Behaviors and side effects * Only affects active offers * Handles both offer purchases and offer grants * Deactivates all associated product memberships tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, removes tag relationship to contact resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" required: - data patch: summary: Replace offers for contact description: | ## Replace offer grant(s) for a contact 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"}] } ``` ## Response * A successful response body will list the offers related to the contact * An error response will include a JSON body with error details. tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, replaces offers relationships of contact resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" required: - data "/v1/contacts/{contact_id}/relationships/tags": get: summary: List contact's tags description: | Get the contact's relationship to tags, response is a list of resource identifiers Response is a list of resource identifiers ```json { "data": [ { "type": "contact_tags", "id": "123" }, { "type": "contact_tags", "id": "456" } ] } ``` The related tag resources are available using the GET `api/v1/contact_tags` endpoint. The resource identifier includes the contact tag id and type. Example URLs: `/api/v1/contact_tags/123`, `/api/v1/contact_tags/456` tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, shows details for tags relationship content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" post: summary: Add tag to contact description: | Add tag relationships to contact resource using a list of resource identifiers Request body includes a list of resource identifiers, `id: CONTACT_TAG_ID`, `type: "contact_tags"`. ```json { "data": [{ "type": "contact_tags", "id": "456" }] } ``` The response body will include the updated list of tag relationships. Example response body: ```json { "data": [{ "type": "contact_tags", "id": "123" }, { "type": "contact_tags", "id": "456" }] } ``` tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, adds tag relationship to contact resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" required: - data delete: summary: Remove tag from contact description: | Remove tag relationships to contact resource using a list of resource identifiers. Request body includes a list of resource identifiers, `id: CONTACT_TAG_ID`, `type: "contact_tags"`. ```json { "data": [{ "type": "contact_tags", "id": "456" }] } ``` The response body will include the updated list of tag relationships. Example response body: ```json { "data": [{ "type": "contact_tags", "id": "123" }] } ``` tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, removes tag relationship to contact resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" required: - data patch: summary: Replace tags for contact description: | Replace tag relationships to contact resource using a list of resource identifiers. Request body includes a list of resource identifiers, `id: CONTACT_TAG_ID`, `type: "contact_tags"`. ```json { "data": [{ "type": "contact_tags", "id": "123" }, { "type": "contact_tags", "id": "456" }] } ``` The response body will include the updated list of tag relationships. ```json { "data": [{ "type": "contact_tags", "id": "123" }, { "type": "contact_tags", "id": "456" }] } ``` tags: - Contacts security: - Bearer: [] parameters: - name: contact_id in: path required: true schema: type: string responses: '200': description: Success, replaces tag relationships of contact resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" required: - data "/v1/courses": get: summary: List courses description: | List of courses that can be offered to a contact or purchased ## Pagination Use the `page[number]` and `page[size]` query parameters to paginate results: ### Get first page of 10 items * `GET /v1/courses?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/courses?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 } } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by title in ascending order * `GET /v1/courses?sort=title` ### Sort by title in descending order * `GET /v1/courses?sort=-title` Response will include courses sorted by the specified field ```json { "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" } } ] } ``` ## Sparse Fields Use the `fields` parameter to request only specific attributes: ### Only return title and thumbnail_url attributes * `GET /v1/courses?fields[courses]=title,thumbnail_url` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "courses", "attributes": { "title": "Marketing Fundamentals", "thumbnail_url": "https://example.com/thumbnail.jpg" } }] } ``` ## Filter by Site ID Use the `filter[site_id]` parameter to get courses for a specific site: ### Get courses for site with ID 123 * `GET /v1/courses?filter[site_id]=123` Response will only include courses for that site ```json { "data": [{ "id": "456", "type": "courses", "attributes": { "title": "Marketing Fundamentals", "description": "Introduction to marketing concepts", "status": "active" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Filter by Title Contains Use the `filter[title_cont]` parameter to find courses where the title contains specific text: ### Get courses with titles containing "marketing" * `GET /v1/courses?filter[title_cont]=marketing` Response will include courses with matching titles ```json { "data": [{ "id": "456", "type": "courses", "attributes": { "title": "Marketing Fundamentals", "description": "Introduction to marketing concepts", "status": "active" } }] } ``` ## Filter by Description Contains Use the `filter[description_cont]` parameter to find courses where the description contains specific text: ### Get courses with descriptions containing "marketing" * `GET /v1/courses?filter[description_cont]=marketing` Response will include courses with matching descriptions ```json { "data": [{ "id": "456", "type": "courses", "attributes": { "title": "Marketing Fundamentals", "description": "Introduction to marketing concepts and strategies", "status": "active" } }] } ``` ## Using Multiple Parameters Together You can combine pagination, sparse fields, filtering and sorting in a single request: ### Get first page of 10 courses for site 123, sorted by title, showing only specific fields * `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 ```json { "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 } } ``` tags: - Courses security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title, for descending order use ''-'' e.g. &sort=-title' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[courses] in: query required: false description: Partial attributes as specified, e.g. fields[courses]=title,thumbnail_url schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=marketing schema: type: string - name: filter[description_cont] in: query required: false description: Filter by description contains, for example ?filter[description_cont]=marketing schema: type: string - name: filter[publish_status_eq] in: query required: false description: Filter by publish status, for example ?filter[publish_status_eq]=published schema: type: string responses: '200': description: Success, list of courses which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/courses_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/courses/{id}": get: summary: Course details description: | Details of a course that can be offered to a contact or purchased ## Course Attributes * `created_at` (string) - The date and time the course was created * `title` (string) - The title of the course * `description` (string) - The description of the course * `thumbnail_url` (string) - The URL of the course thumbnail ## Including Relationships Use the `include` query parameter to load related resources: ### Include modules, lessons and related media, and offers * `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) ```json { "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" } }] } } ``` ## Module attributes 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: * Identify and display the module in the course outline * Organize related lessons/content * Provide navigation structure in the course * The title must be unique within a course. * `description` (string) - An optional text field that provides additional information about the module's content. This can be used to: * Give students an overview of what they'll learn * Explain the module's objectives * Provide context for the contained lessons * Help students understand the module's purpose in the course structure * `position` (integer) - A numeric field that determines the order of modules within a course. This: * Used for sorting * Allows modules to be reordered * Maintains the course's logical progression * Is used for navigation between modules * Starts at position 1 for the first module * `poster_image_url` (string) - A URL to an image that represents the module visually. This: * Can be uploaded through the Kajabi admin interface * Is used as a thumbnail/preview image * Helps with visual organization of the course * `publishing_option` (string) - Controls the visibility and availability of the module. Options include: * `published` - Module is visible and available to students * `draft` - Module is hidden and not yet available * Can be used with drip settings for timed release * Affects the visibility of contained lessons * Syncs with the course's overall publishing status ## Lesson attributes Lessons 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: * Must be present * Has a maximum length of 200 characters * Is used for display and navigation * Can be searched (using pg_search) * Is used in course outlines and navigation * `position` (integer) - A numeric field that determines the order of lessons within a module (category). This: * Usedfor sorting (ranks :sort, column: :position) * Is scoped within each module * Allows lessons to be reordered * Maintains the logical flow of content * Is used for navigation between lessons * `status` (string) - An field that tracks the lesson's processing state: * `ready` - Default state, lesson is ready for use * `duplicating` - Lesson is being copied * `failed` - An error occurred during processing * This is particularly relevant for lessons with media content or during duplication. * `publishing_option` (string) - Controls the visibility and availability of the lesson. Options include: * `draft` - Lesson is hidden and not yet available to students * `published` - Lesson is visible and available (sets publish_at to current time) * `drip` - Lesson becomes available after a specified number of days * `locked` - Lesson is locked until certain conditions are met (e.g., completing previous lessons) ## Media attributes * `duration_in_minutes` (float) - The length of a media file (typically video or audio) in minutes. ## Sparse Fields Use the `fields` parameter to request only specific attributes: ### Only return title and thumbnail_url attributes * `GET /v1/courses/123?fields[courses]=title,thumbnail_url` Response will only include requested fields ```json { "data": { "id": "123", "type": "courses", "attributes": { "title": "Marketing Fundamentals", "thumbnail_url": "https://example.com/thumbnail.jpg" } } } ``` ## Using Multiple Parameters Together You can combine sparse fields and include in a single request: ### Get course details with modules and lessons, showing only specific fields * `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 ```json { "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 } }] } ``` tags: - Courses security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: Load the related resources, for example ?include=modules,lessons,lessons.media schema: type: string responses: '200': description: Success, shows details of a course content: application/vnd.api+json: schema: "$ref": "#/components/schemas/courses_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/custom_fields": get: summary: List custom fields description: | ## Custom Field attributes The 'handle' attribute may be used as a key for a contact resource, e.g. custom_1, custom_2, custom_3 ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/custom_fields?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/custom_fields?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 } } ``` ## Filter by Site ID Use the `filter[site_id]` parameter to get custom fields for a specific site: ### Get custom fields for site with ID 123 * `GET /v1/custom_fields?filter[site_id]=123` Response will only include custom fields for that site ```json { "data": [ { "id": "123", "type": "custom_fields", "attributes": { "handle": "custom_1", "title": "Favorite Song", "type": "TextField", "required": false }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } } ] } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by title in ascending order * `GET /v1/custom_fields?sort=title` ### Sort by title in descending order * `GET /v1/custom_fields?sort=-title` ## Filter by Title Contains Use the `filter[title_cont]` parameter to find custom fields where the title contains specific text: ### Get custom fields with titles containing "favorite" * `GET /v1/custom_fields?filter[title_cont]=favorite` Response will include custom fields with matching titles ```json { "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 } }] } ``` ## Filter by Required Field Use the `filter[required_eq]` parameter to find custom fields based on their required status: ### Get custom fields that are required * `GET /v1/custom_fields?filter[required_eq]=true` Response will include custom fields that are required ```json { "data": [{ "id": "123", "type": "custom_fields", "attributes": { "handle": "custom_1", "title": "Phone Number", "type": "TextField", "required": true } }] } ``` ## Using Multiple Parameters Together You can combine pagination, sorting, sparse fields and filtering in a single request: ### Get page 2 of custom fields for site 123, sorted by title descending, including only handle and title fields * `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 ```json { "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 } } ``` tags: - Custom Fields security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title, handle, type, required for descending order use ''-'' e.g. &sort=-title' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[custom_fields] in: query required: false description: Partial attributes as specified, e.g. fields[custom_fields]=handle,title,required schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=favorite schema: type: string - name: filter[type_eq] in: query required: false description: Filter by field type equals, for example ?filter[type_eq]=TextField schema: type: string - name: filter[required_eq] in: query required: false description: Filter by required field equals, for example ?filter[required_eq]=true schema: type: string responses: '200': description: Success, list of custom fields which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/custom_fields_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/custom_fields/{id}": get: summary: Custom field details description: | ## Custom Field attributes * `handle` (string) - The key for a `contact` resource, e.g. `custom_1`, `custom_2`, `custom_3` * `title` (string) - The title of the custom field * `type` (string) - The type of the custom field * `required` (boolean) - Whether the custom field is required * `archived` (boolean) - Whether the custom field is archived ## Sparse Fields Use the `fields[custom_fields]` parameter to include only specific attributes: ### Include only handle and title fields * `GET /v1/custom_fields/123?fields[custom_fields]=handle,title` Response will include only the specified fields ```json { "data": { "id": "123", "type": "custom_fields", "attributes": { "handle": "custom_1", "title": "Favorite Song" } } } ``` tags: - Custom Fields security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: fields[custom_fields] in: query required: false description: Partial attributes as specified, e.g. fields[custom_fields]=title,handle schema: type: string responses: '200': description: Success, shows details of a custom field content: application/vnd.api+json: schema: "$ref": "#/components/schemas/custom_fields_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/customers": get: summary: List customers description: | List of customers ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/customers?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/customers?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 * The default Sorting is by created_at in descending order (newest first) 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: ### Sort by name in ascending order * `GET /v1/customers?filter[site_id]=123&sort=name` ### Sort by email in descending order * `GET /v1/customers?filter[site_id]=123&sort=-email` ### Sort by net_revenue in ascending order * `GET /v1/customers?filter[site_id]=123&sort=net_revenue` ### Sort by last_request_at in descending order * `GET /v1/customers?filter[site_id]=123&sort=-last_request_at` Response will include customers sorted by the specified field ```json { "data": [{ "id": "123", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "external_user_id": "cust_123" } }] } ``` ## Sparse Fields Use the `fields[customers]` parameter to request only specific attributes: ### Only return name and email attributes * `GET /v1/customers?fields[customers]=name,email` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com" } }] } ``` ## Filtering Use the `filter[site_id]` parameter to filter customers by site: ### Get customers for site with ID 123 * `GET /v1/customers?filter[site_id]=123` Response will include only customers from the specified site ```json { "data": [{ "id": "456", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "external_user_id": "cust_123" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Using Indexed Data Search ```json { "data": [{ "id": "456", "type": "customers", "attributes": { "name": "John Smith", "email": "smith.john@example.com" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Using Multiple Filters You can combine multiple filter parameters to refine your search: ### Get customers from site 123 matching search term * `GET /v1/customers?filter[site_id]=123&filter[search]=smith` Response will include only customers from the specified site matching the search term ```json { "data": [{ "id": "456", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "external_user_id": "cust_123" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Filtering by Site and Offer You can filter customers by both site and offer ownership: ### Get customers from site 123 who have been granted offer 789 * `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 ```json { "data": [{ "id": "456", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "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" } } } }] } ``` ## Filtering by Site and Product You can filter customers by both site and product ownership: ### Get customers from site 123 who have purchased product 789 * `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 ```json { "data": [{ "id": "456", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "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" } } } }] } ``` ## Using Multiple Parameters Together You can combine filtering, sparse fields, pagination and search in a single request: ### Get page 2 of customers from site 123, including only name and email fields, searching for "smith" * `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 ```json { "data": [{ "id": "456", "type": "customers", "attributes": { "name": "John Smith", "email": "john.smith@example.com" } }], "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 } } ``` tags: - Customers security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: name, email, created_at, net_revenue, last_request_at for descending order use ''-'' e.g. &sort=-name' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[customers] in: query required: false description: 'Sparse fields, use: name, email for example ?fields[customers]=name,email' schema: type: string - name: filter[site_id] in: query required: false description: It is recommended to always filter by site_id, for example ?filter[site_id]=111. This param is required when the account has multiple sites schema: type: string - name: filter[search] in: query required: false description: Filter with fuzzy search of name/email, for example ?filter[search]=alexa schema: type: string - name: filter[created_in_last] in: query required: false description: Filter customers created in the last N days, e.g. ?filter[created_in_last]=30 schema: type: string - name: filter[not_created_in_last] in: query required: false description: Filter customers not created in the last N days schema: type: string - name: filter[is_hidden] in: query required: false description: Filter hidden customers schema: type: string - name: filter[joined_in_last] in: query required: false description: Filter customers who joined in the last N days schema: type: string - name: filter[active_in_last] in: query required: false description: Filter customers active in the last N days schema: type: string - name: filter[inactive_in_last] in: query required: false description: Filter customers inactive in the last N days schema: type: string - name: filter[name_contains] in: query required: false description: Filter customers whose name contains the given value schema: type: string - name: filter[email_contains] in: query required: false description: Filter customers whose email contains the given value schema: type: string - name: filter[phone_number_contains] in: query required: false description: Filter customers whose phone number contains the given value schema: type: string - name: filter[address_line_1_contains] in: query required: false description: Filter customers whose address line 1 contains the given value schema: type: string - name: filter[address_line_2_contains] in: query required: false description: Filter customers whose address line 2 contains the given value schema: type: string - name: filter[address_city_contains] in: query required: false description: Filter customers whose city contains the given value schema: type: string - name: filter[address_state_contains] in: query required: false description: Filter customers whose state contains the given value schema: type: string - name: filter[address_country_contains] in: query required: false description: Filter customers whose country contains the given value schema: type: string - name: filter[address_zip_contains] in: query required: false description: Filter customers whose zip code contains the given value schema: type: string - name: filter[has_tag_id] in: query required: false description: Filter customers with a specific tag ID schema: type: string - name: filter[has_all_tag_id] in: query required: false description: Filter customers with all specified tag IDs schema: type: string - name: filter[has_no_tag_id] in: query required: false description: Filter customers without the specified tag ID schema: type: string - name: filter[subscribed] in: query required: false description: Filter subscribed customers schema: type: string - name: filter[has_offer_id] in: query required: false description: Filter customers with a specific offer ID schema: type: string - name: filter[has_no_offer_id] in: query required: false description: Filter customers without the specified offer ID schema: type: string - name: filter[has_product_id] in: query required: false description: Filter customers who own a specific product ID schema: type: string - name: filter[has_active_product_id] in: query required: false description: Filter customers with an active membership to a specific product ID schema: type: string - name: filter[has_no_product_id] in: query required: false description: Filter customers who do not own a specific product ID schema: type: string - name: filter[previously_owned_product_id] in: query required: false description: Filter customers who previously owned a specific product ID schema: type: string - name: filter[used_coupon_code] in: query required: false description: Filter customers who used a specific coupon code schema: type: string - name: filter[submitted_form_id] in: query required: false description: Filter customers who submitted a specific form ID schema: type: string - name: filter[no_submitted_form_id] in: query required: false description: Filter customers who have not submitted the specified form ID schema: type: string - name: filter[registered_event_id] in: query required: false description: Filter customers who registered for a specific event ID schema: type: string - name: filter[not_registered_event_id] in: query required: false description: Filter customers who have not registered for the specified event ID schema: type: string - name: filter[completed_assessment_id] in: query required: false description: Filter customers who completed a specific assessment ID schema: type: string - name: filter[passed_assessment_id] in: query required: false description: Filter customers who passed a specific assessment ID schema: type: string - name: filter[failed_assessment_id] in: query required: false description: Filter customers who failed a specific assessment ID schema: type: string - name: filter[net_revenue_equal_to] in: query required: false description: Filter customers whose net revenue equals the given value schema: type: string - name: filter[net_revenue_greater_than] in: query required: false description: Filter customers whose net revenue is greater than the given value schema: type: string - name: filter[net_revenue_less_than] in: query required: false description: Filter customers whose net revenue is less than the given value schema: type: string - name: filter[subscribed_in_last] in: query required: false description: Filter customers subscribed in the last N days schema: type: string - name: filter[unsubscribed_in_last] in: query required: false description: Filter customers unsubscribed in the last N days schema: type: string - name: filter[never_subscribed] in: query required: false description: Filter customers who have never subscribed schema: type: string - name: filter[sent_email_broadcast_id] in: query required: false description: Filter customers who were sent a specific email broadcast ID schema: type: string - name: filter[no_sent_email_broadcast_id] in: query required: false description: Filter customers who were not sent the specified email broadcast ID schema: type: string - name: filter[no_sent_email_broadcast_ids] in: query required: false description: Filter customers who were not sent any of the specified email broadcast IDs schema: type: string - name: filter[no_delivered_email_broadcast_id] in: query required: false description: Filter customers who did not receive the specified email broadcast ID schema: type: string - name: filter[opened_email_broadcast_id] in: query required: false description: Filter customers who opened a specific email broadcast ID schema: type: string - name: filter[no_opened_email_broadcast_id] in: query required: false description: Filter customers who did not open the specified email broadcast ID schema: type: string - name: filter[clicked_email_broadcast_id] in: query required: false description: Filter customers who clicked a specific email broadcast ID schema: type: string - name: filter[no_clicked_email_broadcast_id] in: query required: false description: Filter customers who did not click the specified email broadcast ID schema: type: string - name: filter[bounced_email_broadcast_id] in: query required: false description: Filter customers who bounced a specific email broadcast ID schema: type: string - name: filter[no_bounced_email_broadcast_id] in: query required: false description: Filter customers who did not bounce the specified email broadcast ID schema: type: string - name: filter[dropped_email_broadcast_id] in: query required: false description: Filter customers who dropped a specific email broadcast ID schema: type: string - name: filter[no_dropped_email_broadcast_id] in: query required: false description: Filter customers who did not drop the specified email broadcast ID schema: type: string - name: filter[opened_email_in_last] in: query required: false description: Filter customers who opened an email in the last N days schema: type: string - name: filter[not_opened_email_in_last] in: query required: false description: Filter customers who did not open an email in the last N days schema: type: string - name: filter[delivered_email_in_last] in: query required: false description: Filter customers who were delivered an email in the last N days schema: type: string - name: filter[not_delivered_email_in_last] in: query required: false description: Filter customers who were not delivered an email in the last N days schema: type: string - name: filter[clicked_email_in_last] in: query required: false description: Filter customers who clicked an email in the last N days schema: type: string - name: filter[not_clicked_email_in_last] in: query required: false description: Filter customers who did not click an email in the last N days schema: type: string - name: filter[is_hard_bouncing] in: query required: false description: Filter customers that are hard bouncing schema: type: string - name: filter[bounced_in_last] in: query required: false description: Filter customers who bounced in the last N days schema: type: string - name: filter[complained_in_last] in: query required: false description: Filter customers who complained in the last N days schema: type: string - name: filter[manually_unsubscribed_in_last] in: query required: false description: Filter customers manually unsubscribed in the last N days schema: type: string - name: filter[opted_out_in_last] in: query required: false description: Filter customers who opted out in the last N days schema: type: string - name: filter[healthy_contacts_with_open_data] in: query required: false description: Filter healthy customers with open data schema: type: string - name: filter[passive_contacts_with_open_data] in: query required: false description: Filter passive customers with open data schema: type: string - name: filter[unengaged_contacts_with_open_data] in: query required: false description: Filter unengaged customers with open data schema: type: string - name: filter[inactive_contacts_with_open_data] in: query required: false description: Filter inactive customers with open data schema: type: string - name: filter[subscribed_newsletter_id] in: query required: false description: Filter customers subscribed to a specific newsletter ID schema: type: string - name: filter[unsubscribed_newsletter_id] in: query required: false description: Filter customers unsubscribed from a specific newsletter ID schema: type: string - name: filter[mobile_phone_number_contains] in: query required: false description: Filter customers whose mobile phone number contains the given value schema: type: string - name: filter[subscribed_email_sequence_id] in: query required: false description: Filter customers subscribed to a specific email sequence ID schema: type: string - name: filter[not_subscribed_email_sequence_id] in: query required: false description: Filter customers not subscribed to a specific email sequence ID schema: type: string responses: '200': description: Success, filter by product ownership content: application/vnd.api+json: schema: "$ref": "#/components/schemas/customers_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/customers/{id}": get: summary: Customer details description: | Show customer details * The `name` and `email` attributes are kept in sync with the related `contact` resource * The `external_user_id` attribute may be used as a customer reference in an external system ## Customer Attributes * `name` (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. ## Include Related Resources Use the `include` parameter to include related resources: ### Include offers and products * `GET /v1/customers/123?include=contact,offers,products` Response will include related resources ```json { "data": { "id": "123", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com", "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": "alice@example.com", "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" } } ] } ``` ## Sparse Fields Use the `fields[customers]` parameter to request only specific attributes: ### Only return name and email attributes * `GET /v1/customers/123?fields[customers]=name,email` Response will only include requested fields ```json { "data": { "id": "123", "type": "customers", "attributes": { "name": "Alice Smith", "email": "alice@example.com" } } } ``` ## Using Multiple Parameters Together 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 ```json { "data": { "id": "123", "type": "customers", "attributes": { "name": "Alice Smith" }, "relationships": {} }, "included": [ { "id": "789", "type": "products", "attributes": { "title": "Course 1" } } ] } ``` tags: - Customers security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: with ?include=offers,products the response will include the related resources schema: type: string - name: fields[customers] in: query required: false description: Partial attributes as specified, e.g. fields[customers]=name,email schema: type: string - name: include in: query required: false schema: type: string - name: filter[products_search] in: query required: false description: Search products by title schema: type: string - name: include in: query required: false schema: type: string - name: filter[products_page] in: query required: false schema: type: integer - name: filter[products_per] in: query required: false schema: type: integer - name: include in: query required: false schema: type: string - name: filter[offers_search] in: query required: false description: Search offers by title or internal title schema: type: string - name: include in: query required: false schema: type: string - name: filter[offers_page] in: query required: false schema: type: integer - name: filter[offers_per] in: query required: false schema: type: integer - name: include in: query required: false schema: type: string - name: filter[products_search] in: query required: false schema: type: string - name: filter[offers_search] in: query required: false schema: type: string - name: filter[products_search] in: query required: false description: Should be ignored when include parameter is missing schema: type: string - name: filter[offers_search] in: query required: false description: Should be ignored when include parameter is missing schema: type: string responses: '200': description: Success - filters ignored when include parameter not present content: application/vnd.api+json: schema: "$ref": "#/components/schemas/customers_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/customers/{customer_id}/relationships/offers": get: summary: List customer's offers description: | Get the customer's relationship to offers (granted). Response is a list of resource identifiers ```json { "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` tags: - Customers security: - Bearer: [] parameters: - name: customer_id in: path required: true schema: type: string responses: '200': description: Success, shows details for tags relationship content: application/vnd.api+json: schema: "$ref": "#/components/schemas/customers_relationships_offers_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" post: summary: Grant offer to customer description: | ## Grant offer(s) to a customer 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"}] } ``` ## Response * A successful response body will list the offers related to the customer * An error response will include a JSON body with error details. ## Behaviors and side effects * Checks if the customerwas already granted the offer * May send a gift granted email if this is a gift offer * Triggers automations if configured tags: - Customers security: - Bearer: [] parameters: - name: customer_id in: path required: true schema: type: string responses: '200': description: Success, offer (granted) using relationship to customer resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/customers_relationships_offers_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" required: - data delete: summary: Revoke offer from customer description: | ## Revoke offer grant(s) for a customer 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"}] } ``` ## Response * A successful response body will list the offers related to the customer * An error response will include a JSON body with error details. ## Behaviors and side effects * Only affects active offers * Handles both offer purchases and offer grants * Deactivates all associated product memberships tags: - Customers security: - Bearer: [] parameters: - name: customer_id in: path required: true schema: type: string responses: '200': description: Success, revokes offer from customer resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/customers_relationships_offers_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" required: - data patch: summary: Replace offers for customer description: | ## Replace offer grant(s) for a customer 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"}] } ``` ## Response * A successful response body will list the offers related to the customer * An error response will include a JSON body with error details. tags: - Customers security: - Bearer: [] parameters: - name: customer_id in: path required: true schema: type: string responses: '200': description: Success, replaces offers relationships of contact resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/customers_relationships_offers_response" '400': description: Bad Request, invalid request body content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_bad_request" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" required: - data "/v1/form_submissions": get: summary: List form submissions description: | Form submissions for authorized sites ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/form_submissions?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/form_submissions?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/form_submissions?page[number]=2&page[size]=10", "first": "https://api.kajabi.com/v1/form_submissions?page[number]=1&page[size]=10", "prev": "https://api.kajabi.com/v1/form_submissions?page[number]=1&page[size]=10", "next": "https://api.kajabi.com/v1/form_submissions?page[number]=3&page[size]=10", "last": "https://api.kajabi.com/v1/form_submissions?page[number]=5&page[size]=10" }, "meta": { "total_pages": 5, "total_count": 50, "current_page": 2 } } ``` ## Filtering Use filter parameters to narrow down results: ### Filter by site ID * `GET /v1/form_submissions?filter[site_id]=123` ### Filter by form ID * `GET /v1/form_submissions?filter[form_id]=456` ## Sorting Use the `sort` parameter to sort results: ### Sort by creation date (oldest first) * `GET /v1/form_submissions?sort=created_at` ### Sort by name (alphabetical) * `GET /v1/form_submissions?sort=name` tags: - Forms security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: name, email, created_at. For descending order use ''-'' e.g. &sort=-name' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: filter[site_id] in: query required: false description: 'Filter by site ID, example: filter[site_id]=123' schema: type: string - name: filter[form_id] in: query required: false description: 'Filter by form ID, example: filter[form_id]=456' schema: type: string responses: '200': description: Success, filtered by form_id content: application/vnd.api+json: schema: "$ref": "#/components/schemas/form_submissions_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/form_submissions/{id}": get: summary: Form submission details description: | Shows details of a form submission ## Form Submission Attributes * `name` (string) - The name of the person who submitted the form * `email` (string) - The email address of the person who submitted the form * `address_line_1` (string) - First line of address if provided * `address_line_2` (string) - Second line of address if provided * `address_city` (string) - City if provided * `address_country` (string) - Country if provided * `address_state` (string) - State if provided * `address_zip` (string) - ZIP/postal code if provided * `phone_number` (string) - Phone number if provided * `business_number` (string) - Business number if provided * `mobile_phone_number` (string) - Mobile phone number if provided ## Custom Fields Form submissions may also include custom field values that were collected through the form. ## Relationships Form submissions belong to: * A site * A form ## Include Related Resources Use the `include` parameter to load related resources: ### Include site and form * `GET /v1/form_submissions/123?include=site,form` tags: - Forms security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: Load the related resources, for example ?include=site,form schema: type: string responses: '200': description: Success, shows details of a form submission content: application/vnd.api+json: schema: "$ref": "#/components/schemas/form_submissions_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Form submission not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/forms": get: summary: List forms description: | Contact forms for a site ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/forms?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/forms?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 } } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by title in ascending order * `GET /v1/forms?sort=title` ### Sort by title in descending order * `GET /v1/forms?sort=-title` Response will include forms sorted by the specified field ```json { "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" } } ] } ``` ## Sparse Fields Use the `fields[forms]` parameter to request only specific attributes: ### Only return title and description attributes * `GET /v1/forms?fields[forms]=title,description` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "forms", "attributes": { "title": "Contact Form A", "description": "General contact form" } }] } ``` ## Filter by Site ID Use the `filter[site_id]` parameter to get forms for a specific site: ### Get forms for site with ID 123 * `GET /v1/forms?filter[site_id]=123` Response will only include forms for that site ```json { "data": [{ "id": "456", "type": "forms", "attributes": { "title": "Contact Form A", "description": "General contact form" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Filter by Title Contains Use the `filter[title_cont]` parameter to find forms where the title contains specific text: ### Get forms with titles containing "course" * `GET /v1/forms?filter[title_cont]=course` Response will include forms with matching titles ```json { "data": [{ "id": "456", "type": "forms", "attributes": { "title": "Course Registration Form", "description": "Sign up form for online courses" } }] } ``` ## Using Multiple Parameters Together You can combine pagination, sorting, sparse fields and filtering in a single request: ### Get page 2 of forms for site 123, sorted by title descending, including only title and description fields * `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 ```json { "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 } } ``` tags: - Forms security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title for descending order use ''-'' e.g. &sort=-title' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: fields[forms] in: query required: false description: Partial attributes as specified, e.g. fields[forms]=title schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=course schema: type: string responses: '200': description: Success, list of forms which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/forms_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/forms/{id}": get: summary: Form details description: | Shows details of a form Forms belong to a site and can be associated with: * Landing pages * Offers * Email sequences * Events * Newsletters ## Form Attributes * `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: * Must be a valid URL format * Cannot be a redirecting URL * Is automatically transformed and validated * Can be used to send form submission data to external services * `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. ## Include Related Resources Use the `include` parameter to load related resources: ### Include fields, offer, contact_tags * `GET /v1/forms/123?include=fields,offer,contact_tags` Response will include the requested related resources ```json { "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" } } ] } ``` ### Field Attributes Fields are used in: * Contact forms * Offer forms * Custom field sets * Form submissions 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 input * `PhoneField` - Phone number input * `EmailField` - Email address input * `TextAreaField` - Multi-line text input * `CheckboxField` - Boolean checkbox * `SelectBoxField` - Dropdown select * `RadioButtonsField` - Radio button group * `CountryField` - Country selector * `MobilePhoneField` - Mobile phone input * `required` (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. * A custom handle in the format custom_N where N is a number from 1 to 150 * The handle is used to reference the field in code and templates. * `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. ## Sparse Fields Use the `fields[forms]` parameter to request only specific attributes: ### Only return title and webhook_url attributes * `GET /v1/forms/123?fields[forms]=title,webhook_url` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "forms", "attributes": { "title": "Contact Form A", "webhook_url": "https://example.com/webhook" } }] } ``` ## Using Multiple Parameters Together You can combine include and sparse fields in a single request: ### Include fields (only name attribute) and only return title and webhook_url attributes * `GET /v1/forms/123?include=fields&fields[forms]=title,webhook_url&&fields[fields]=title` Response will include related fields with sparse fields ```json { "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" } } ] } ``` tags: - Forms security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: Load the related resources, for example ?include=fields,site,offer,contact_tags schema: type: string - name: fields[forms] in: query required: false description: Partial attributes as specified, e.g. fields[forms]=title,webhook_url schema: type: string responses: '200': description: Success, shows details of a form content: application/vnd.api+json: schema: "$ref": "#/components/schemas/forms_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: form not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/forms/{id}/submit": post: summary: Submit form description: | ## Submit a form * The `name` and `email` attributes are required. * The `email` attribute must be a valid and deliverable email address. Example request body: ```json { "data": { "type": "form_submissions", "attributes": { "name": "John Doe", "email": "john.doe@example.com" } } } ``` Response will include the newly created form submission resource. ```json { "data": { "id": "313", "type": "form_submissions", "attributes": { "name": "John Doe", "email": "john.doe@example.com", "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" } } } } } ``` ## Behaviors and side effects * Checks for disposable emails * Validates email deliverability * Sends double opt-in email if needed * Subscribes contact (with opt-in handling) * Subscribes to SMS if applicable * Adds tags to contact * Grants offers if configured * Subscribes to email sequences * Delivers webhooks * Triggers automations tags: - Forms security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string responses: '201': description: Success, shows the form submission data content: application/vnd.api+json: schema: "$ref": "#/components/schemas/form_submission_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: object properties: type: type: string attributes: "$ref": "#/components/schemas/form_submission_attributes" required: - type - attributes required: - data "/v1/hooks": get: summary: List hooks description: | Lists webhooks for a site ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/hooks?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/hooks?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/hooks?page[number]=2&page[size]=10", "first": "https://api.kajabi.com/v1/hooks?page[number]=1&page[size]=10", "prev": "https://api.kajabi.com/v1/hooks?page[number]=1&page[size]=10", "next": "https://api.kajabi.com/v1/hooks?page[number]=3&page[size]=10", "last": "https://api.kajabi.com/v1/hooks?page[number]=5&page[size]=10" }, "meta": { "total_pages": 5, "total_count": 50, "current_page": 2 } } ``` ## Filtering Use `filter[event_eq]` parameter to filter webhooks by event type: ### Get webhooks for purchase events only * `GET /v1/hooks?filter[event_eq]=purchase` tags: - Webhooks security: - Bearer: [] parameters: - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: filter[event_eq] in: query required: false schema: type: string enum: - purchase - form_submission - tag_added - tag_removed - payment_succeeded - order_created description: Filter by event type, for example ?filter[event_eq]=purchase responses: '200': description: Success, list of hooks which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/hooks_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" post: summary: Create hook description: | Creates a new webhook subscription ## Request Body The request must include: * `data` - parent object which includes the children/nested attributes: * `target_url` - The URL where webhook events will be sent * `event` - The type of event to subscribe to (see available events below), for example "tag_added" * `resource_id` (optional) - Specific resource ID to filter events for, for example the id of the Contact Tag. When the property is omitted, the webhook will be triggered for all events of the specified type, as a wildcard webhook. ## Available Event Types | Event | Description | Required API Scopes | |-------|-------------|-------------------| | `purchase` | Customer makes a purchase | `view:purchases` | | `payment_succeeded` | Payment transaction completes successfully | `view:transactions` | | `order_created` | New order is created | `view:transactions`, `view:orders` | | `form_submission` | Someone submits a form | `view:form_submissions` | | `tag_added` | Tag is added to a contact | `view:contacts` | | `tag_removed` | Tag is removed from a contact | `view:contacts` | **Note**: You can only create webhooks for events you have permission to access based on your API key scopes. For example to use tags you need the `view:contacts` scope, which is included in the account owner api key scope. ## Sample Payloads You can view sample webhook payloads for each event type: * `GET /v1/hooks/purchase_sample` * `GET /v1/hooks/payment_succeeded_sample` * `GET /v1/hooks/order_created_sample` * `GET /v1/hooks/form_submission_sample` * `GET /v1/hooks/tag_added_sample` * `GET /v1/hooks/tag_removed_sample` Example request targeting a specific tag: ```json { "data": { "type": "hooks", "attributes": { "target_url": "https://example.com/webhook", "event": "tag_added", "resource_id": "123" }, "relationships": { "site": { "data": { "id": "456", "type": "sites" } } } } } ``` Example request using a wildcard webhook: ```json { "data": { "type": "hooks", "attributes": { "target_url": "https://example.com/webhook", "event": "tag_added" }, "relationships": { "site": { "data": { "id": "456", "type": "sites" } } } } } ``` ## Actual Payloads The actual payloads are sent to the `target_url` as a POST request with the following JSON body: ```json { "id": "hash_id", "event": "tag_added", "payload": [], } ``` The `id` is the ID of the resource that triggered the event. The `event` is the type of event that triggered the webhook. The `payload` is the actual payload of the event and the content will be similar to the sample payloads above. tags: - Webhooks security: - Bearer: [] parameters: [] responses: '201': description: Success, webhook created content: application/vnd.api+json: schema: "$ref": "#/components/schemas/hooks_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '422': description: Unprocessable Entity, invalid parameters content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unprocessable" requestBody: content: application/vnd.api+json: schema: type: object properties: data: type: object properties: type: type: string enum: - hooks attributes: "$ref": "#/components/schemas/hooks_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" required: - site required: - type - attributes - relationships required: - data "/v1/hooks/{id}": get: summary: Hook details description: Returns specific hook based on it ID tags: - Webhooks security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string responses: '200': description: Success, webhook retrieved content: application/vnd.api+json: schema: "$ref": "#/components/schemas/hooks_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not Found, webhook does not exist content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" delete: summary: Delete hook description: Deletes a webhook subscription tags: - Webhooks security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string responses: '204': description: Success, webhook deleted '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not Found, webhook does not exist content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/hooks/tag_added_sample": get: summary: Tag added sample description: | Returns sample webhook payload for the `tag_added` event: ``` [ { "id": "0", "type": "contacts", "attributes": { "name": "Sample Recipient", "email": "sample@example.com", "address_line_1": "123 Kajabi Ln", "address_line_2": "Kajabi Suite 4", "address_city": "Kajabiwood", "address_country": "United Sites of Kajabi", "address_state": "Kajabifornia", "address_zip": "99999", "phone_number": "5555555555", "business_number": null, "subscribed": false, "external_user_id": null, "created_at": "2025-07-31T16:51:04.010Z", "updated_at": "2025-07-31T16:51:04.010Z" }, "links": { "customer": "" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } } } }, { "id": "0", "type": "contact_tags", "attributes": { "name": "Tag" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } } } } ] ``` ## Actual Payloads The actual payloads are sent to the `target_url` as a POST request with the following JSON body: ```json { "id": "hash_id", "event": "tag_added", "payload": [], } ``` The `payload` array is the sample response above tags: - Webhooks security: - Bearer: [] responses: '200': description: Success, returns sample webhook payload content: application/vnd.api+json: schema: type: array items: anyOf: - type: object properties: id: type: string type: type: string enum: - contacts attributes: "$ref": "#/components/schemas/contacts_attributes" relationships: type: object properties: tags: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - contact_tags - type: object properties: id: type: string type: type: string enum: - contact_tags attributes: "$ref": "#/components/schemas/contact_tags_attributes" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/hooks/tag_removed_sample": get: summary: Tag removed sample description: | Returns sample webhook payload for the `tag_removed` event: ``` [ { "id": "0", "type": "contacts", "attributes": { "name": "Sample Recipient", "email": "sample@example.com", "address_line_1": "123 Kajabi Ln", "address_line_2": "Kajabi Suite 4", "address_city": "Kajabiwood", "address_country": "United Sites of Kajabi", "address_state": "Kajabifornia", "address_zip": "99999", "phone_number": "5555555555", "business_number": null, "subscribed": false, "external_user_id": null, "created_at": "2025-07-31T16:51:04.010Z", "updated_at": "2025-07-31T16:51:04.010Z" }, "links": { "customer": "" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } } } }, { "id": "0", "type": "contact_tags", "attributes": { "name": "Tag" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } } } } ] ``` ## Actual Payloads The actual payloads are sent to the `target_url` as a POST request with the following JSON body: ```json { "id": "hash_id", "event": "tag_removed", "payload": [], } ``` The `payload` array is the sample response above tags: - Webhooks security: - Bearer: [] responses: '200': description: Success, returns sample webhook payload content: application/vnd.api+json: schema: type: array items: anyOf: - type: object properties: id: type: string type: type: string enum: - contacts attributes: "$ref": "#/components/schemas/contacts_attributes" relationships: type: object properties: tags: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - contact_tags - type: object properties: id: type: string type: type: string enum: - contact_tags attributes: "$ref": "#/components/schemas/contact_tags_attributes" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/hooks/form_submission_sample": get: summary: Form submission sample description: | Returns sample webhook payload for the `form_submission` event: ``` [ { "id": "0", "type": "form_submissions", "attributes": { "name": "John Doe", "email": "john.doe@example.com", "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": "0", "type": "forms" } } } }, { "id": "0", "type": "forms", "attributes": { "url": "https://bill-heaton.kajabi-products.test/forms/0", "title": "Sample Form", "default": false, "webhook_url": null, "created_at": null, "updated_at": null }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } }, "fields": { "data": [] }, "contact_tags": { "data": [] } } } ] ``` ## Actual Payloads The actual payloads are sent to the `target_url` as a POST request with the following JSON body: ```json { "id": "hash_id", "event": "form_submission", "payload": [], } ``` The `payload` array is the sample response above tags: - Webhooks security: - Bearer: [] responses: '200': description: Success, returns sample webhook payload content: application/vnd.api+json: schema: type: array items: anyOf: - type: object properties: id: type: string type: type: string enum: - form_submissions attributes: "$ref": "#/components/schemas/form_submission_attributes" relationships: type: object properties: tags: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - forms - type: object properties: id: type: string type: type: string enum: - forms attributes: "$ref": "#/components/schemas/form_attributes" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/hooks/purchase_sample": get: summary: Purchase sample description: | Returns sample webhook payload for the `purchase` event: ``` [ { "id": "0", "type": "purchases", "attributes": { "amount_in_cents": 1000, "payment_type": "single", "multipay_payments_made": null, "opt_in": false, "raw_extra_contact_information": {}, "currency": "USD", "effective_start_at": null, "cardholder_name": null, "billing_address_zip": null, "deactivated_at": null, "deactivation_reason": null, "coupon_code": null, "source": null, "referrer": null, "quantity": 1, "created_at": "2025-07-31T16:59:27.580Z", "updated_at": "2025-07-31T16:59:27.580Z" }, "relationships": { "customer": { "data": { "id": "0", "type": "customers" } }, "offer": { "data": { "id": "0", "type": "offers" } }, "products": { "data": [] } } }, { "id": "0", "type": "offers", "attributes": { "title": "Kajabi Test Offer", "description": null, "internal_title": null, "currency": "USD", "price_in_cents": 1000, "payment_type": "single", "token": "n8NtoHUZ", "image_url": null, "payment_method": "stripe_and_paypal", "price_description": "$10.00 USD", "checkout_url": "https://bill-heaton.kajabi-products.test/offers/n8NtoHUZ", "recurring_offer": false, "subscription": false, "one_time": true, "single": true, "free": false }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } }, "products": { "data": [] }, "forms": { "data": [] } } }, { "id": "0", "type": "customers", "attributes": { "name": "John Doe", "email": "john.doe@example.com", "avatar": null, "external_user_id": null, "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": "2025-07-31T16:59:27.552Z", "updated_at": "2025-07-31T16:59:27.552Z" }, "links": { "contact": "https://www.kajabi.test/api/v1/contacts/0" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } }, "contact": { "data": { "id": "0", "type": "contacts" } }, "offers": { "data": [], "links": { "self": "https://www.kajabi.test/api/v1/customers/0/relationships/offers" } }, "products": { "data": [] } } } ] ``` ## Actual Payloads The actual payloads are sent to the `target_url` as a POST request with the following JSON body: ```json { "id": "hash_id", "event": "purchase", "payload": [], } ``` The `payload` array is the sample response above tags: - Webhooks security: - Bearer: [] responses: '200': description: Success, returns sample webhook payload content: application/vnd.api+json: schema: type: array items: anyOf: - type: object properties: id: type: string type: type: string enum: - purchases attributes: "$ref": "#/components/schemas/purchases_attributes" relationships: type: object properties: customer: type: object properties: data: type: object properties: id: type: string type: type: string enum: - customers offers: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - offers products: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - offers - type: object properties: id: type: string type: type: string enum: - customers attributes: "$ref": "#/components/schemas/customers_attributes" - type: object properties: id: type: string type: type: string enum: - offers attributes: "$ref": "#/components/schemas/offers_attributes" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/hooks/payment_succeeded_sample": get: summary: Payment succeeded sample description: | Returns sample webhook payload for the `payment_succeeded` event: ``` [ { "id": "0", "type": "transactions", "attributes": { "action": "charge", "state": "succeeded", "payment_type": "charge", "amount_in_cents": 1000, "sales_tax_in_cents": 0, "currency": "USD", "currency_symbol": "$", "formatted_amount": "$10.00", "created_at": "2025-07-31T17:10:19.285Z" }, "relationships": { "customer": { "data": { "id": "0", "type": "customers" } }, "offer": { "data": null } } }, { "id": "0", "type": "customers", "attributes": { "name": "John Doe", "email": "john.doe@example.com", "avatar": null, "external_user_id": null, "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": "2025-07-31T17:10:19.243Z", "updated_at": "2025-07-31T17:10:19.243Z" }, "links": { "contact": "https://www.kajabi.test/api/v1/contacts/0" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } }, "contact": { "data": { "id": "0", "type": "contacts" } }, "offers": { "data": [], "links": { "self": "https://www.kajabi.test/api/v1/customers/0/relationships/offers" } }, "products": { "data": [] } } } ] ``` ## Actual Payloads The actual payloads are sent to the `target_url` as a POST request with the following JSON body: ```json { "id": "hash_id", "event": "payment_succeeded", "payload": [], } ``` The `payload` array is the sample response above tags: - Webhooks security: - Bearer: [] responses: '200': description: Success, returns sample webhook payload content: application/vnd.api+json: schema: type: array items: anyOf: - type: object properties: id: type: string type: type: string enum: - transactions attributes: "$ref": "#/components/schemas/transactions_attributes" relationships: type: object properties: customer: type: object properties: data: type: object properties: id: type: string type: type: string enum: - customers offer: type: object properties: data: type: object properties: id: type: string type: type: string enum: - offers nullable: true - type: object properties: id: type: string type: type: string enum: - customers attributes: "$ref": "#/components/schemas/customers_attributes" - type: object properties: id: type: string type: type: string enum: - offers attributes: "$ref": "#/components/schemas/offers_attributes" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/hooks/order_created_sample": get: summary: Order created sample description: | Returns sample webhook payload for the `order_created` event: ``` [ { "id": "0", "type": "transactions", "attributes": { "action": "charge", "state": "succeeded", "payment_type": "charge", "amount_in_cents": 1000, "sales_tax_in_cents": 0, "currency": "USD", "currency_symbol": "$", "formatted_amount": "$10.00", "created_at": "2025-07-31T17:13:05.247Z" }, "relationships": { "customer": { "data": { "id": "0", "type": "customers" } }, "offer": { "data": null } } }, { "id": "0", "type": "customers", "attributes": { "name": "John Doe", "email": "john.doe@example.com", "avatar": null, "external_user_id": null, "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": "2025-07-31T17:13:05.207Z", "updated_at": "2025-07-31T17:13:05.207Z" }, "links": { "contact": "https://www.kajabi.test/api/v1/contacts/0" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } }, "contact": { "data": { "id": "0", "type": "contacts" } }, "offers": { "data": [], "links": { "self": "https://www.kajabi.test/api/v1/customers/0/relationships/offers" } }, "products": { "data": [] } } }, { "id": "0", "type": "orders", "attributes": { "order_number": 0, "currency_code": "USD", "fulfilled_at": null, "created_at": "2025-07-31T17:13:05.207Z", "total_price_in_cents": 1000, "subtotal_in_cents": 800, "sales_tax_amount_in_cents": 200, "discount_amount_in_cents": 0, "formatted_total_price": "$10.00", "formatted_subtotal": "$8.00", "currency_symbol": "$" }, "relationships": { "site": { "data": { "id": "2", "type": "sites" } }, "customer": { "data": { "id": "0", "type": "customers" } }, "order_items": { "data": [ { "id": "0", "type": "order_items" } ] }, "payment_transactions": { "data": [] } } }, { "id": "0", "type": "order_items", "attributes": { "quantity": 1, "currency_code": "USD", "item_type": "Offer", "item_id": 0, "title": "Kajabi Test Offer", "fulfilled_at": null, "created_at": "2025-07-31T17:13:05.229Z", "total_price_in_cents": 1000, "subtotal_in_cents": 800, "sales_tax_amount_in_cents": 200, "discount_amount_in_cents": 0, "formatted_total_price": "$10.00", "formatted_subtotal": "$8.00", "currency_symbol": "$" }, "relationships": { "order": { "data": { "id": "0", "type": "orders" } } } } ] ``` ## Actual Payloads The actual payloads are sent to the `target_url` as a POST request with the following JSON body: ```json { "id": "hash_id", "event": "order_created", "payload": [], } ``` The `payload` array is the sample response above tags: - Webhooks security: - Bearer: [] responses: '200': description: Success, returns sample webhook payload content: application/vnd.api+json: schema: type: array items: anyOf: - type: object properties: id: type: string type: type: string enum: - transactions attributes: "$ref": "#/components/schemas/transactions_attributes" relationships: type: object properties: customer: type: object properties: data: type: object properties: id: type: string type: type: string enum: - customers offer: type: object properties: data: type: object properties: id: type: string type: type: string enum: - offers nullable: true - type: object properties: id: type: string type: type: string enum: - customers attributes: "$ref": "#/components/schemas/customers_attributes" - type: object properties: id: type: string type: type: string enum: - offers attributes: "$ref": "#/components/schemas/offers_attributes" - type: object properties: id: type: string type: type: string enum: - orders attributes: "$ref": "#/components/schemas/orders_attributes" relationships: type: object properties: site: type: object properties: data: type: object properties: id: type: string type: type: string enum: - sites customer: type: object properties: data: type: object properties: id: type: string type: type: string enum: - customers order_items: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - order_items payment_transactions: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - transactions - type: object properties: id: type: string type: type: string enum: - order_items attributes: "$ref": "#/components/schemas/order_items_attributes" relationships: type: object properties: order: type: object properties: data: type: object properties: id: type: string type: type: string enum: - orders '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/kajabi_payments_payouts": get: summary: List payouts description: | List of Kajabi Payments payouts for a site. Payouts represent transfers of funds from Kajabi to the site owner's connected bank account or payment method. **Note**: Date fields are returned in UTC: * `initiated_date` - Payout creation timestamp in UTC * `estimated_arrival_date` - Expected arrival timestamp in UTC ## Pagination Use `page[number]` parameter to paginate results: ### Get first page * `GET /v1/kajabi_payments_payouts?page[number]=1&filter[site_id]=123` ### Get second page * `GET /v1/kajabi_payments_payouts?page[number]=2&filter[site_id]=123` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/kajabi_payments_payouts?page[number]=2&filter[site_id]=123", "first": "https://api.kajabi.com/v1/kajabi_payments_payouts?page[number]=1&filter[site_id]=123", "prev": "https://api.kajabi.com/v1/kajabi_payments_payouts?page[number]=1&filter[site_id]=123", "next": "https://api.kajabi.com/v1/kajabi_payments_payouts?page[number]=3&filter[site_id]=123", "last": "https://api.kajabi.com/v1/kajabi_payments_payouts?page[number]=5&filter[site_id]=123" }, "meta": { "total": 50, "pagination": { "current": 2, "first": 1, "prev": 1, "next": 3, "last": 5, "records": 10, } } } ``` ## Filtering by Site Use the `filter[site_id]` parameter to filter payouts by site (required): ### Get payouts for site with ID 123 * `GET /v1/kajabi_payments_payouts?filter[site_id]=123` ## Filtering by Status Use the `filter[status]` parameter to filter payouts by status: ### Get paid payouts for site with ID 123 * `GET /v1/kajabi_payments_payouts?filter[site_id]=123&filter[status]=paid` Valid status values: * `pending` - The payout has been created but hasn't been submitted to the bank yet * `in_transit` - The payout has been submitted to the bank and is being processed * `paid` - The payout succeeded and the money has successfully reached your bank account * `failed` - Something went wrong and the payout couldn't be transferred to your account * `canceled` - The payout was canceled before it could complete ## Date Range Filtering Use the `filter[start_date]` and `filter[end_date]` parameters to filter payouts by date range: ### Get payouts between January 1st and January 31st, 2024 * `GET /v1/kajabi_payments_payouts?filter[site_id]=123&filter[start_date]=2024-01-01&filter[end_date]=2024-01-31` Response will include only payouts within the specified date range. ## Using Multiple Parameters Together You can combine multiple parameters to filter the response: ### Get paginated, filtered payouts * `GET /v1/kajabi_payments_payouts?page[number]=1&filter[site_id]=123&filter[status]=paid&filter[start_date]=2024-01-01&filter[end_date]=2024-01-31` Response will include paginated payouts matching all filters: ```json { "data": [{ "id": "payout_abc123", "type": "kajabi_payments_payouts", "attributes": { "status": "Paid", "amount": 1500.00, "currency": "USD", "initiated_date": "2024-01-10T10:00:00.000Z", "estimated_arrival_date": "2024-01-17T10:00:00.000Z", "bank_account": "Chase Bank - 1234" } }] } ``` tags: - Kajabi Payments Payouts security: - Bearer: [] parameters: - name: page[number] in: query required: false description: Page number for pagination, for example ?page[number]=2 schema: type: number - name: filter[site_id] in: query required: true description: Site ID to fetch payouts for (required), for example ?filter[site_id]=123 schema: type: string - name: filter[status] in: query required: false description: Filter by payout status (pending, paid, failed, canceled), for example ?filter[status]=paid schema: type: string - name: filter[start_date] in: query required: false description: Filter payouts after this date (ISO 8601), for example ?filter[start_date]=2024-01-01 schema: type: string - name: filter[end_date] in: query required: false description: Filter payouts before this date (ISO 8601), for example ?filter[end_date]=2024-12-31 schema: type: string responses: '200': description: Success, returns empty list when no payouts exist '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/kajabi_payments_payouts/{id}": get: summary: Get payout details description: | Get detailed information about a specific Kajabi Payments payout, including all associated transactions. **Note**: Date fields are returned in UTC: * `initiated_date` - Payout creation timestamp in UTC * `estimated_arrival_date` - Expected arrival timestamp in UTC * `transactions[].created_at` - Transaction timestamp in UTC ## Transaction Fields Each transaction in the `transactions` array includes: * **Transaction Type** - Whether or not this transaction was a sale, refund, or adjustment * **Pricing Type** - When this is a sale this is the offer's pricing type, i.e. one-time, subscription, or payment plan * **Sales Tax** - The sales tax collected for this transaction * **Amount** - The transaction amount * **Currency** - Three-letter currency code (USD, EUR, GBP, etc.) * **Fee** - The transaction processing fee * **Net** - The transaction net amount (amount - fee) * **Customer ID** - Customer ID associated with the transaction * **Customer Name** - Customer's full name * **Customer Email** - Customer's email address * **Offer ID** - When a sale or refund, the ID(s) of the purchased offer * **Offer Title** - When a sale or refund, the title(s) of the purchased offer * **Provider** - The payment processor (Kajabi Payments, Stripe, PayPal, etc.) * **Payment Method** - For a sale or refund, the payment method that was used (Credit Card, etc.) * **Created At** - When the transaction occurred (in UTC) * **Coupon Used** - For a sale or refund, the coupon code if one was applied * **Presented Amount** - The transaction original transaction amount (before currency conversion) * **Presented Currency** - The transaction original currency code * **Exchange Rate** - The currency exchange rate applied * **Quantity** - The quantity of the offer that was purchased * **Order Number** - For a sale or refund, the order number when an order was purchased ## Transaction Types * `Sale` - All payments and that were received as part of this payout * `Refund` - Any refunds that occurred as part of this payout * `Adjustment` - All other adjustments that occurred as a part of this payout ## Example Response ```json { "data": { "id": "payout_abc123", "type": "kajabi_payments_payouts", "attributes": { "status": "Paid", "amount": 1450.50, "currency": "USD", "initiated_date": "2024-01-10T10:00:00.000Z", "estimated_arrival_date": "2024-01-17T10:00:00.000Z", "bank_account": "Chase Bank - 1234", "transactions": [ { "transaction_type": "Sales", "pricing_type": "Subscription", "sales_tax": 0.0, "amount": 99.00, "currency": "USD", "fee": 3.17, "net": 95.83, "customer_id": 789, "customer_name": "John Doe", "customer_email": "john@example.com", "offer_ids": [ 101 ], "offer_titles": [ "Premium Membership" ], "provider": "Kajabi Payments", "payment_method": "Visa", "created_at": "2024-01-08T14:30:00.000Z", "coupon_used": "SAVE20", "presented_amount": 99.00, "presented_currency": "USD", "exchange_rate": 1.0, "quantity": 1, "order_number": "ORD-12345" } ] } } } ``` tags: - Kajabi Payments Payouts security: - Bearer: [] parameters: - name: id in: path required: true description: Payout ID, for example payout_abc123 schema: type: string - name: filter[site_id] in: query required: true description: Site ID to authorize access (required), for example ?filter[site_id]=123 schema: type: string responses: '200': description: Success, returns payout details with all transactions '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not Found, payout does not exist or user doesn't have access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/landing_pages": get: summary: List landing pages description: | Returns a list of landing pages which the current user may access ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/landing_pages[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/landing_pages[number]=2&page[size]=25` ## Sparse Fields Use the `fields[landing_pages]` parameter to request only specific attributes: ### Only return title attribute * `GET /v1/landing_pages?fields[landing_pages]=title` ## Sorting Use the `sort` parameter to sort the results: ### Sort by publish_at in descending order * `GET /v1/landing_pages?sort=-publish_at&fields[landing_pages]=title` ## Filters Use the `filter[site_id]` parameter to get landing pages for a specific site: ### Get landing pages for site with ID 123 * `GET /v1/landing_pages?filter[site_id]=123` List of attributes that may be used to filter: title, publish_at, created_at, updated_at The filter param uses the following syntax: `filter[attribute_name_suffix]` with suffix for comparison: * `eq` for equals * `cont` for contains * `not_eq` for not equals * `not_cont` for not contains * `gt` for greater than * `gte` for greater than or equal * `lt` for less than * `lte` for less than or equal * `start` for starts with * `end` for ends with For example: * `GET /v1/landing_pages?filter[title_start]=Course` * `GET /v1/landing_pages?filter[title_cont]=Landing` tags: - Landing pages security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title for descending order use ''-'' e.g. &sort=-title' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: fields[landing_pages] in: query required: false description: Partial attributes as specified, e.g. fields[landing_pages]=title schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=about schema: type: string - name: filter[published] in: query required: false description: Filter by published status, for example ?filter[published]=true schema: type: string responses: '200': description: Success, list of landing pages which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/landing_pages_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/landing_pages/{id}": get: summary: Landing page details description: | Shows details of a landing page ## Landing Page Attributes * `title` (string) - Title of the landing page * `url` (string) - URL of the landing page * `publish_at` (string) - Date and time the landing page will be published * `created_at` (string) - Date and time the landing page was created * `updated_at` (string) - Date and time the landing page was updated ## Sparse Fields ### Only return title attribute * `GET /v1/landing_pages/123?fields[landing_pages]=title` Response will only include requested fields ```json { "data": { "id": "123", "type": "landing_pages", "attributes": { "title": "Course Landing Page" } } } ``` tags: - Landing pages security: - Bearer: [] parameters: - name: id in: path required: true description: Landing page ID schema: type: string - name: fields[landing_pages] in: query required: false description: Partial attributes as specified, e.g. fields[landing_pages]=title schema: type: string responses: '200': description: Success, shows details of a landing page content: application/vnd.api+json: schema: "$ref": "#/components/schemas/landing_pages_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: landing page not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/me": get: summary: My user profile description: | Returns the current user's profile data. ## Response attributes 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: * Set directly as a full name * Automatically generated from first name and last name fields when either changes * Used for display purposes throughout the platform * `email` - The user's email address. This is a critical field that: * Is required and must be unique * Is used for authentication * Can trigger email change notifications * Is used for password recovery * Can be marked as bounced (and reset when email changes) * Is validated against email format requirements * `role_level` - Represents the user's permission level in the system. This attribute: * Common values include: * OWNER - Account owner with full permissions * ADMINISTRATOR - Admin with site management permissions * Determines what actions and resources the user can access * Is used for permission checks throughout the system tags: - Me security: - Bearer: [] responses: '200': description: Success content: application/vnd.api+json: schema: "$ref": "#/components/schemas/me_response" '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/offers": get: summary: List offers description: | List of offers (not archived) for a site that can be granted to a contact ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/offers?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/offers?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 } } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by title in ascending order * `GET /v1/offers?sort=title` ### Sort by title in descending order * `GET /v1/offers?sort=-title` Response will include offers sorted by the specified field ```json { "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" } } ] } ``` ## Sparse Fields Use the `fields[offers]` parameter to request only specific attributes: ### Only return title and price_in_cents attributes * `GET /v1/offers?fields[offers]=title,price_in_cents` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "offers", "attributes": { "title": "Advanced Course Bundle", "price_in_cents": 19900 } }] } ``` ## Filter by Site ID Use the `filter[site_id]` parameter to get offers for a specific site: ### Get offers for site with ID 123 * `GET /v1/offers?filter[site_id]=123` Response will only include offers for that site ```json { "data": [{ "id": "456", "type": "offers", "attributes": { "title": "Advanced Course Bundle", "price_in_cents": 19900, "status": "active" }, "relationships": { "site": { "data": { "id": "123", "type": "sites" } } } }] } ``` ## Filter by Title Contains Use the `filter[title_cont]` parameter to find offers where the title contains specific text: ### Get offers with titles containing "bundle" * `GET /v1/offers?filter[title_cont]=bundle` Response will include offers with matching titles ```json { "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" } }] } ``` ## Filter by Description Contains Use the `filter[description_cont]` parameter to find offers where the description contains specific text: ### Get offers with descriptions containing "marketing" * `GET /v1/offers?filter[description_cont]=marketing` Response will include offers with matching descriptions ```json { "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" } }] } ``` ## Using Multiple Parameters Together You can combine pagination, sorting, sparse fields and filtering in a single request: ### Get page 2 of offers for site 123, sorted by price_in_cents descending, including only title and price_in_cents fields * `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 ```json { "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 } } ``` tags: - Offers security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title, price_in_cents, for descending order use ''-'' e.g. &sort=-price_in_cents' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[offers] in: query required: false description: Partial attributes as specified, e.g. fields[offers]=title,price_in_cents schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=course schema: type: string - name: filter[description_cont] in: query required: false description: Filter by description contains, for example ?filter[description_cont]=course schema: type: string responses: '200': description: Success, list of offers which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/offers_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/offers/{id}": get: summary: Offer details description: | 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. ## Offer attributes * `title` (string) - Required, public name of the offer shown to customers * `description` (string) - Optional, detailed information about what's included in the offer * `internal_title` (string) - Optional, for internal reference/organization (not shown to customers) * `currency` (string) - The currency of the offer, defaults to USD * `price_in_cents` (integer) - The USD price in cents (for precise decimal handling) * `payment_type` (string) - Indicates the payment structure * `token` (string) - A unique identifier for the offer, particularly in checkout URLs * `payment_method` (string) - Indicates the payment method, Returns empty string if no payment method is set * `price_description` (string) - Human-readable representation of the offer's price, includes formatting and currency information * `checkout_url` (string) - Full URL where customers can purchase the offer * Includes the offer token for identification * Uses the site's public host and protocol settings * `recurring_offer` (boolean) - Whether the offer has recurring payments * `subscription` (boolean) - Whether the offer is a subscription offer * `one_time` (boolean) - Whether the offer is a one-time offer * `single` (boolean) - Whether the offer is a single offer * `free` (boolean) - Whether the offer is a free offer * `image_url` (string) - URL to the image associated with the offer (nullable) ## Include Relationships Use the `include` parameter to include related products: * `GET /v1/offers/123?include=products` Response will include products relationship ```json { "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, "image_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", "image_url": "https://api.kajabi.com/images/456" } } ] } ``` ## Sparse Fields ### Only return title and price_in_cents attributes * `GET /v1/offers/123?fields[offers]=title,price_in_cents` Response will only include requested fields ```json { "data": { "id": "123", "type": "offers", "attributes": { "title": "Advanced Course Bundle", "price_in_cents": 19900 } } } ``` ## Multiple parameters together You can combine include and sparse fields in a single request: ### Get offer 123 with products, including only title and description fields, and products with title and publish_status fields * `GET /v1/offers/123?include=products&fields[offers]=title,description&fields[products]=title,publish_status` Response will include offer and products with sparse fields ```json { "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" } } ] } ``` tags: - Offers security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: Load the related resources, for example ?include=products schema: type: string - name: fields[offers] in: query required: false description: Partial attributes as specified, e.g. fields[offers]=title,price_in_cents schema: type: string responses: '200': description: Success, shows details of an offer content: application/vnd.api+json: schema: "$ref": "#/components/schemas/offers_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/offers/{offer_id}/relationships/products": get: summary: List offer's products description: get the offer's relationship to products, response is a list of resource identifiers tags: - Offers security: - Bearer: [] parameters: - name: offer_id in: path required: true schema: type: string responses: '200': description: Success, shows details for tags relationship content: application/vnd.api+json: schema: "$ref": "#/components/schemas/contacts_relationships_tags_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/order_items": get: summary: List order items description: | Order items represent individual products or offers within an order. ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/order_items?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/order_items?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/order_items?page[number]=2&page[size]=10", "first": "https://api.kajabi.com/v1/order_items?page[number]=1&page[size]=10", "prev": "https://api.kajabi.com/v1/order_items?page[number]=1&page[size]=10", "next": "https://api.kajabi.com/v1/order_items?page[number]=3&page[size]=10", "last": "https://api.kajabi.com/v1/order_items?page[number]=5&page[size]=10" }, "meta": { "total_pages": 5, "total_count": 50, "current_page": 2 } } ``` ## Filtering Use filter parameters to narrow down results: ### Filter by site Use the `filter[site_id]` parameter to get order items for a specific site: * `GET /v1/order_items?filter[site_id]=123` ### Filter by item type * `GET /v1/order_items?filter[item_type_eq]=Offer` ### Filter by item ID * `GET /v1/order_items?filter[item_id_eq]=123` ### Filter by fulfilled status * `GET /v1/order_items?filter[fulfilled_at_null]=true` (unfulfilled items) * `GET /v1/order_items?filter[fulfilled_at_null]=false` (fulfilled items) ## Advanced Filtering Examples ### Range queries * `GET /v1/order_items?filter[site_id]=123&filter[quantity_gt]=1` * `GET /v1/order_items?filter[site_id]=123&filter[total_price_in_cents_gteq]=1000&filter[total_price_in_cents_lteq]=10000` ### Pattern matching * `GET /v1/order_items?filter[site_id]=123&filter[item_type_cont]=Off` * `GET /v1/order_items?filter[site_id]=123&filter[title_i_cont]=course` (case insensitive) ### Array filters * `GET /v1/order_items?filter[site_id]=123&filter[item_id_in]=123,456,789` * `GET /v1/order_items?filter[site_id]=123&filter[item_type_not_in]=Bundle,Subscription` ## Sorting Use the `sort` parameter to sort the results: ### Sort by fulfilled_at in ascending order * `GET /v1/order_items?filter[site_id]=123&sort=fulfilled_at` tags: - Orders security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: created_at, quantity, fulfilled_at. For descending order use ''-'' e.g. &sort=-created_at' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: fields[order_items] in: query required: false description: Partial attributes as specified, e.g. fields[order_items]=quantity,title,total_price_in_cents schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[item_type_eq] in: query required: false description: Filter by item type, for example ?filter[item_type_eq]=Offer schema: type: string - name: filter[item_id_eq] in: query required: false description: Filter by item ID, for example ?filter[item_id_eq]=123 schema: type: string - name: filter[fulfilled_at_null] in: query required: false description: Filter by fulfillment status, for example ?filter[fulfilled_at_null]=true schema: type: boolean responses: '200': description: Success, list of order items which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/order_items_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/order_items/{id}": get: summary: Order item details description: | Shows details of an order item Order items represent individual products or offers within an order and contain: * Product/offer information * Pricing details * Quantity information * Fulfillment status ## Order Item Attributes * `quantity` (integer) - Number of items purchased * `currency_code` (string) - The ISO currency code for the item * `item_type` (string) - Type of item (e.g., "Offer") * `item_id` (integer) - ID of the associated item * `title` (string) - Title of the item * `total_price_in_cents` (integer) - Total price for this line item * `subtotal_in_cents` (integer) - Subtotal before taxes and discounts * `sales_tax_amount_in_cents` (integer) - Sales tax amount for this item * `discount_amount_in_cents` (integer) - Discount amount for this item * `fulfilled_at` (string) - Timestamp when the item was fulfilled * `created_at` (string) - Timestamp when the order item was created ## Include Related Resources Use the `include` parameter to load related resources: ### Include order * `GET /v1/order_items/123?include=order` tags: - Orders security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: Load the related resources, for example ?include=order schema: type: string - name: fields[order_items] in: query required: false description: Partial attributes as specified, e.g. fields[order_items]=quantity,title,total_price_in_cents schema: type: string responses: '200': description: Success, shows details of an order item content: application/vnd.api+json: schema: "$ref": "#/components/schemas/order_items_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: order item not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/orders": get: summary: List orders description: | Orders for a site ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/orders?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/orders?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/orders?page[number]=2&page[size]=10", "first": "https://api.kajabi.com/v1/orders?page[number]=1&page[size]=10", "prev": "https://api.kajabi.com/v1/orders?page[number]=1&page[size]=10", "next": "https://api.kajabi.com/v1/orders?page[number]=3&page[size]=10", "last": "https://api.kajabi.com/v1/orders?page[number]=5&page[size]=10" }, "meta": { "total_pages": 5, "total_count": 50, "current_page": 2 } } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by order_number in ascending order * `GET /v1/orders?sort=order_number` ### Sort by created_at in descending order * `GET /v1/orders?sort=-created_at` ## Filtering Use filter parameters to narrow down results: ### Filter by site Use the `filter[site_id]` parameter to get orders for a specific site: * `GET /v1/orders?filter[site_id]=123` ### Filter by customer Use the `filter[customer_id]` parameter to get orders for a specific customer: * `GET /v1/orders?filter[customer_id]=456789` ### Filter by order number * `GET /v1/orders?filter[order_number_eq]=12345` ### Filter by fulfilled status * `GET /v1/orders?filter[fulfilled_at_null]=true` (unfulfilled orders) * `GET /v1/orders?filter[fulfilled_at_null]=false` (fulfilled orders) ## Advanced Filtering Examples ### Range queries * `GET /v1/orders?filter[site_id]=123&filter[created_at_gteq]=2024-01-01&filter[created_at_lteq]=2024-12-31` * `GET /v1/orders?filter[site_id]=123&filter[total_price_in_cents_gt]=5000` ### Pattern matching * `GET /v1/orders?filter[site_id]=123&filter[order_number_cont]=2024` * `GET /v1/orders?filter[site_id]=123&filter[currency_code_start]=US` ### Array filters * `GET /v1/orders?filter[site_id]=123&filter[currency_code_in]=USD,EUR,GBP` tags: - Orders security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: order_number, created_at, fulfilled_at. For descending order use ''-'' e.g. &sort=-created_at' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: fields[orders] in: query required: false description: Partial attributes as specified, e.g. fields[orders]=order_number,total_price_in_cents schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[customer_id] in: query required: false description: Filter by customer_id, for example ?filter[customer_id]=456789 schema: type: string - name: filter[order_number_eq] in: query required: false description: Filter by order number, for example ?filter[order_number_eq]=12345 schema: type: string - name: filter[fulfilled_at_null] in: query required: false description: Filter by fulfillment status, for example ?filter[fulfilled_at_null]=true schema: type: boolean responses: '200': description: Success, list of orders which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/orders_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/orders/{id}": get: summary: Order details description: | Shows details of an order Orders represent completed purchase transactions and contain: * Order items (products/offers purchased) * Payment information * Customer information * Fulfillment status ## Order Attributes * `order_number` (integer) - A unique identifier for the order within the site * `currency_code` (string) - The ISO currency code for the order (e.g., "USD") * `total_price_in_cents` (integer) - Total price including taxes and discounts * `subtotal_in_cents` (integer) - Subtotal before taxes and discounts * `sales_tax_amount_in_cents` (integer) - Total sales tax amount * `discount_amount_in_cents` (integer) - Total discount amount * `fulfilled_at` (string) - Timestamp when the order was fulfilled * `created_at` (string) - Timestamp when the order was created ## Include Related Resources Use the `include` parameter to load related resources: ### Include order items, customer * `GET /v1/orders/123?include=order_items,customer` tags: - Orders security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: include in: query required: false description: Load the related resources, for example ?include=order_items,customer,site schema: type: string - name: fields[orders] in: query required: false description: Partial attributes as specified, e.g. fields[orders]=order_number,total_price_in_cents schema: type: string responses: '200': description: Success, shows details of an order content: application/vnd.api+json: schema: "$ref": "#/components/schemas/orders_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: order not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/podcasts": get: summary: List podcasts description: | Podcasts for a site ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/podcasts?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/podcasts?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/podcasts?page[number]=2&page[size]=10", "first": "https://api.kajabi.com/v1/podcasts?page[number]=1&page[size]=10", "prev": "https://api.kajabi.com/v1/podcasts?page[number]=1&page[size]=10", "next": "https://api.kajabi.com/v1/podcasts?page[number]=3&page[size]=10", "last": "https://api.kajabi.com/v1/podcasts?page[number]=5&page[size]=10" }, "meta": { "total_pages": 5, "total_count": 50, "current_page": 2 } } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by title in ascending order * `GET /v1/podcasts?sort=title` ### Sort by title in descending order * `GET /v1/podcasts?sort=-title` Response will include podcasts sorted by the specified field ```json { "data": [ { "id": "123", "type": "podcasts", "attributes": { "title": "My Podcast A", "description": "A great podcast about technology" } }, { "id": "456", "type": "podcasts", "attributes": { "title": "My Podcast B", "description": "Another great podcast about business" } } ] } ``` ## Sparse Fields Use the `fields[podcasts]` parameter to request only specific attributes: ### Only return title and description attributes * `GET /v1/podcasts?fields[podcasts]=title,description` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "podcasts", "attributes": { "title": "My Podcast A", "description": "A great podcast about technology" } }] } ``` ## Filter by Site ID Use the `filter[site_id]` parameter to get podcasts for a specific site: ### Get podcasts for site with ID 123 * `GET /v1/podcasts?filter[site_id]=123` Response will only include podcasts for that site ```json { "data": [{ "id": "456", "type": "podcasts", "attributes": { "title": "My Podcast", "description": "A great podcast" } }] } ``` tags: - Podcasts security: - Bearer: [] parameters: - name: filter[site_id] in: query required: false description: Filter by site ID, for example ?filter[site_id]=123 schema: type: string - name: filter[title_eq] in: query required: false description: Filter by exact title match, for example ?filter[title_eq]=My Podcast schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title containing text, for example ?filter[title_cont]=technology schema: type: string - name: filter[status_eq] in: query required: false description: Filter by status, for example ?filter[status_eq]=ready schema: type: string - name: filter[show_type_eq] in: query required: false description: Filter by show type, for example ?filter[show_type_eq]=episodic schema: type: string - name: sort in: query required: false description: Sort results by field, for example ?sort=title or ?sort=-title (descending) schema: type: string - name: page[number] in: query required: false description: Page number for pagination, for example ?page[number]=1 schema: type: integer - name: page[size] in: query required: false description: Number of items per page, for example ?page[size]=10 schema: type: integer - name: fields[podcasts] in: query required: false description: Comma-separated list of fields to include, for example ?fields[podcasts]=title,description schema: type: string responses: '200': description: List of podcasts content: application/vnd.api+json: schema: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - podcasts attributes: "$ref": "#/components/schemas/podcasts_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string first: type: string prev: type: string next: type: string last: type: string meta: type: object properties: total_pages: type: integer total_count: type: integer current_page: type: integer '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/podcasts/{id}": get: summary: Show podcast description: | Get details for a specific podcast ## Attributes - **title**: The podcast title - **description**: The podcast description - **language**: The podcast language (e.g., "en", "es") - **owner_email**: The podcast owner's email address - **owner_name**: The podcast owner's name - **status**: The podcast status (ready, importing, failed) - **show_type**: The show type (episodic, serial) - **thumbnail_url**: URL to the podcast thumbnail image - **cover_art_url**: URL to the podcast cover art image - **categories**: Array of podcast categories - **directories**: Array of podcast directories - **migrated_to_url**: URL if podcast has been migrated - **migrated**: Boolean indicating if podcast has been migrated - **public**: Boolean indicating if podcast is public - **ready**: Boolean indicating if podcast is ready - **distribution_ready**: Boolean indicating if podcast is ready for distribution - **created_at**: ISO 8601 date-time when podcast was created (read-only) - **updated_at**: ISO 8601 date-time when podcast was last updated (read-only) tags: - Podcasts security: - Bearer: [] parameters: - name: id in: path required: true description: Podcast ID schema: type: string responses: '200': description: Podcast details content: application/vnd.api+json: schema: type: object properties: data: type: object properties: id: type: string type: type: string enum: - podcasts attributes: "$ref": "#/components/schemas/podcasts_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" '401': description: Unauthorized content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not Found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/products": get: summary: List products description: | List of products (not archived) that can be granted to a contact ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/products?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/products?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 } } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by title in ascending order * `GET /v1/products?sort=title` ### Sort by title in descending order * `GET /v1/products?sort=-title` Response will include products sorted by the specified field ```json { "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" } } ] } ``` ## Sparse Fields Use the `fields[products]` parameter to request only specific attributes: ### Get only title and publish_status fields * `GET /v1/products?fields[products]=title,publish_status` Response will only include the requested fields ```json { "data": [ { "id": "123", "type": "products", "attributes": { "title": "Advanced Course", "publish_status": "published" } }, { "id": "456", "type": "products", "attributes": { "title": "Beginner Course", "publish_status": "draft" } } ] } ``` ## Filter by Site ID Use the `filter[site_id]` parameter to get products for a specific site: ### Get products for site with ID 123 * `GET /v1/products?filter[site_id]=123` Response will only include products for that site ```json { "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" } } } } ] } ``` ## Filter by Title Contains Use the `filter[title_cont]` parameter to find products where the title contains specific text: ### Get products with titles containing "course" * `GET /v1/products?filter[title_cont]=course` Response will include products with matching titles ```json { "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" } }] } ``` ## Filter by Description Contains Use the `filter[description_cont]` parameter to find products where the description contains specific text: ### Get products with descriptions containing "training" * `GET /v1/products?filter[description_cont]=training` Response will include products with matching descriptions ```json { "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" } }] } ``` ## Filter by Status Use the `filter[status_eq]` parameter to find products with a specific status: ### Get ready products * `GET /v1/products?filter[status_eq]=ready` Response will include products with matching status ```json { "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" } }] } ``` ## Filter by Excluded Product Types Use the `filter[exclude_product_types][]` parameter to exclude products by productizable_type (fully-qualified class name): ### Exclude CohortCourse products * `GET /v1/products?filter[exclude_product_types][]=Courses::CohortCourse` Response will exclude products with the specified productizable_type while keeping legacy evergreen courses visible. ## Using Multiple Parameters Together You can combine pagination, sorting, sparse fields and filtering in a single request: ### Get page 2 of products for site 123, sorted by title descending, including only title and publish_status fields * `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 ```json { "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 } } ``` tags: - Products security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title, description, status, for descending order use ''-'' e.g. &sort=-title' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[products] in: query required: false description: Partial attributes as specified, e.g. fields[products]=title,publish_status schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=marketing schema: type: string - name: filter[description_cont] in: query required: false description: Filter by description contains, for example ?filter[description_cont]=marketing schema: type: string - name: filter[status_eq] in: query required: false description: Filter by status equals, for example ?filter[status_eq]=ready schema: type: string - name: filter[exclude_product_types][] in: query schema: type: array items: type: string required: false description: Exclude products by productizable_type (fully-qualified, e.g. Courses::CohortCourse). Repeatable. responses: '200': description: Success, list of products which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/products_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/products/{id}": get: summary: Product details description: | Show details of a product ## Sparse Fields Use the `fields[products]` parameter to request only specific attributes: ### Get only title and publish_status fields * `GET /v1/products/123?fields[products]=title,publish_status` Response will only include the requested fields ```json { "data": { "id": "123", "type": "products", "attributes": { "title": "Advanced Course", "publish_status": "published" }, "relationships": {} } } ``` tags: - Products security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: fields[products] in: query required: false description: Partial attributes as specified, e.g. fields[products]=title,publish_status schema: type: string responses: '200': description: Success, shows details of a product content: application/vnd.api+json: schema: "$ref": "#/components/schemas/products_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/purchases": get: summary: List purchases description: | Returns a list of purchases (offer purchases) which the current user may access ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/purchases?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/purchases?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "links": { "self": "https://api.kajabi.com/v1/purchases?page[number]=2&page[size]=10", "first": "https://api.kajabi.com/v1/purchases?page[number]=1&page[size]=10", "prev": "https://api.kajabi.com/v1/purchases?page[number]=1&page[size]=10", "next": "https://api.kajabi.com/v1/purchases?page[number]=3&page[size]=10", "last": "https://api.kajabi.com/v1/purchases?page[number]=5&page[size]=10" }, "meta": { "count": 10, "total_count": 50, "total_pages": 5 } } ``` ## Sparse Fields Use the `fields[purchases]` parameter to request only specific attributes: ### Only return amount_in_cents attributes * `GET /v1/purchases?fields[purchases]=amount_in_cents` Response will only include requested fields ```json { "data": [ { "id": "123", "type": "purchases", "attributes": { "amount_in_cents": 19900 } }, { "id": "456", "type": "purchases", "attributes": { "amount_in_cents": 9900 } } ] } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by effective_start_at in descending order * `GET /v1/purchases?sort=-effective_start_at&fields[purchases]=effective_start_at` Response will include purchases sorted by the specified field ```json { "data": [ { "id": "123", "type": "purchases", "attributes": { "effective_start_at": "2025-01-02T00:00:00.000Z" } }, { "id": "456", "type": "purchases", "attributes": { "effective_start_at": "2025-01-01T00:00:00.000Z" } } ] } ``` List of attributes that may be used to sort: multipay_payments_made, opt_in, currency, effective_start_at, cardholder_name, billing_address_zip, deactivated_at, deactivation_reason, coupon_code, source, referrer, quantity, created_at, updated_at ## Filters Use the `filter[site_id]` parameter to get purchases for a specific site: ### Get purchases for site with ID 123 * `GET /v1/purchases?filter[site_id]=123` ### Filter by customer Use the `filter[customer_id]` parameter to get purchases for a specific customer: * `GET /v1/purchases?filter[customer_id]=456789` List of attributes that may be used to filter: multipay_payments_made, opt_in, currency, effective_start_at, cardholder_name, billing_address_zip, deactivated_at, deactivation_reason, coupon_code, source, referrer, quantity, created_at, updated_at The filter param uses the following syntax: `filter[attribute_name_suffix]` with suffix for comparison: * `eq` for equals * `cont` for contains * `not_eq` for not equals * `not_cont` for not contains * `gt` for greater than * `gte` for greater than or equal * `lt` for less than * `lte` for less than or equal * `start` for starts with * `end` for ends with For example: * `GET /v1/purchases?filter[amount_in_cents_eq]=19900` * `GET /v1/purchases?filter[amount_in_cents_gt]=19900` tags: - Purchases security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: created_at for descending order use ''-'' e.g. &sort=-created_at' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: fields[purchases] in: query required: false description: Partial attributes as specified, e.g. fields[purchases]=amount_in_cents schema: type: string - name: filter[active] in: query required: false description: Filter by active purchases (not deactivated), for example ?filter[active]=true schema: type: boolean - name: filter[deactivated] in: query required: false description: Filter by deactivated purchases, for example ?filter[deactivated]=true schema: type: boolean - name: filter[referrer] in: query required: false description: Filter by referrer, for example ?filter[referrer_cont]=••••• schema: type: string - name: filter[coupon_code_eq] in: query required: false description: Filter by coupon code, for example ?filter[coupon_code_eq]=••••• schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[customer_id] in: query required: false description: Filter by customer_id, for example ?filter[customer_id]=456789 schema: type: string responses: '200': description: Success, list of purchases which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/purchases_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/purchases/{id}": get: summary: Purchase details description: | Details of a purchase (of an offer) ## Purchase Attributes * `amount_in_cents` (integer) - Price of the purchase in cents * `payment_type` (string) - Type of payment * `trial` (integer) - Number of trial days. (subscription and payment plans only) * `trial_end_at` (string) - Date the trial ends * `multipay_payments_made` (integer) - Number of payments made * `payment_plan_total_payments` (integer) - Total number of payments in the payment plan * `status` (string) - The status of the purchase. For one-time purchases this will match the transaction detail status. For subscriptions and payment plans this status represents the status of the plan as compared to the transaction status which represents the individual payment. * `opt_in` (boolean) - Whether the purchase was opt-in * `raw_extra_contact_information` (object) - Extra contact information * `currency` (string) - Currency of the purchase * `effective_start_at` (string) - Start date of the purchase * `cardholder_name` (string) - Name of the cardholder * `billing_address_zip` (string) - Zip code of the billing address * `deactivated_at` (string) - Date and time the purchase was deactivated * `deactivation_reason` (string) - Reason for deactivation * `coupon_code` (string) - Coupon code used for the purchase * `source` (string) - Source of the purchase * `referrer` (string) - Referrer of the purchase * `quantity` (integer) - Quantity of the purchase * `created_at` (string) - Date and time the purchase was created * `updated_at` (string) - Date and time the purchase was updated_at ## Sparse Fields ### Only return amount_in_cents and multipay_payments_made attributes * `GET /v1/purchases/123?fields[purchases]=amount_in_cents,multipay_payments_made` Response will only include requested fields ```json { "data": { "id": "123", "type": "purchases", "attributes": { "amount_in_cents": 19900, "multipay_payments_made": 1 } } } ``` tags: - Purchases security: - Bearer: [] parameters: - name: id in: path required: true description: Purchase ID schema: type: string - name: fields[purchases] in: query required: false description: Partial attributes as specified, e.g. fields[purchases]=amount_in_cents schema: type: string responses: '200': description: Success, shows details of a purchase content: application/vnd.api+json: schema: "$ref": "#/components/schemas/purchases_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/purchases/{id}/reactivate": post: summary: Reactivate purchase description: | Reactivate a purchase by ID, this will not reactivate the subscription. If the product can be reactivated the response will be successful. Otherwise, the response will be an error. tags: - Purchases security: - Bearer: [] parameters: - name: id in: path required: true description: Purchase ID schema: type: string responses: '200': description: Success, reactivated purchase content: application/vnd.api+json: schema: "$ref": "#/components/schemas/purchases_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/purchases/{id}/deactivate": post: summary: Deactivate purchase description: | Deactivate a purchase by ID, this will not cancel the subscription. Use the `cancel_subscription` endpoint to cancel the subscription. Otherwise, the purchase will be deactivated and the subscription will remain active. For a free purchase, the purchase may be later reactivated. If the product can be deactivated the response will be successful. Otherwise, the response will be an error. tags: - Purchases security: - Bearer: [] parameters: - name: id in: path required: true description: Purchase ID schema: type: string responses: '200': description: Success, deactivated purchase content: application/vnd.api+json: schema: "$ref": "#/components/schemas/purchases_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" "/v1/purchases/{id}/cancel_subscription": post: summary: Cancel subscription description: | Cancel the subscription associated with a purchase by ID This endpoint cancels the underlying subscription (Stripe, PayPal, or Kajabi Payments) associated with the purchase. The purchase will be deactivated and the subscription will be cancelled immediately, according to the payment provider's cancellation rules. If the payment can be cancelled the response will be successful. Otherwise, the response will be an error with validation details. tags: - Purchases security: - Bearer: [] parameters: - name: id in: path required: true description: Purchase ID schema: type: string responses: '200': description: Success, cancelled subscription and deactivated purchase content: application/vnd.api+json: schema: "$ref": "#/components/schemas/purchases_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: Not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" '422': description: Unprocessable Entity, validation errors in cancelling subscription content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unprocessable" "/v1/sites": get: summary: List sites description: |+ List of sites that the current user has access to ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/sites?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/sites?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 } } ``` ## Sorting Use the `sort` parameter to sort the results: ### Sort by title in ascending order * `GET /v1/sites?sort=title` ### Sort by title in descending order * `GET /v1/sites?sort=-title` Response will include sites sorted by the specified field ```json { "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" } } ] } ``` ## Sparse Fields Use the `fields[sites]` parameter to request only specific attributes: ### Only return title and subdomain attributes * `GET /v1/sites?fields[sites]=title,subdomain` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "sites", "attributes": { "title": "Advanced Training Site", "subdomain": "advanced-training" } }] } ``` ## Filter by Title Contains Use the `filter[title_cont]` parameter to find sites where the title contains specific text: ### Get sites with titles containing "training" * `GET /v1/sites?filter[title_cont]=training` Response will include sites with matching titles ```json { "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" } }] } ``` ## Filter by Subdomain Contains Use the `filter[subdomain_cont]` parameter to find sites where the subdomain contains specific text: ### Get sites with subdomains containing "training" * `GET /v1/sites?filter[subdomain_cont]=training` Response will include sites with matching subdomains ```json { "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" } }] } ``` ## Using Multiple Parameters Together You can combine pagination, sorting and sparse fields in a single request: ### Get page 2 of sites, sorted by title descending, including only title and subdomain fields * `GET /v1/sites?page[number]=2&page[size]=10&sort=-title&fields[sites]=title,subdomain` Response will include paginated sites with sparse fields ```json { "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 } } ``` tags: - Sites security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: title, subdomain, for descending order use ''-'' e.g. &sort=-title' schema: type: string - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[sites] in: query required: false description: Partial attributes as specified, e.g. fields[sites]=title,subdomain schema: type: string - name: filter[title_cont] in: query required: false description: Filter by title contains, for example ?filter[title_cont]=training schema: type: string - name: filter[subdomain_cont] in: query required: false description: Filter by subdomain contains, for example ?filter[subdomain_cont]=training schema: type: string responses: '200': description: Success, lists sites which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/sites_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/sites/{id}": get: summary: Site details description: | 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. ## Site Attributes * `title` (string) - A required field that represents the name of the site * `subdomain` (string) - The subdomain of the site, used for routing and site identification * `created_at` (string) - A read-only timestamp, ISO date string format, that indicates when the site was created * `updated_at` (string) - A read-only timestamp, ISO date string format, that indicates when the site was last modified ## Sparse Fields Use the `fields[sites]` parameter to request only specific attributes: ### Only return title and subdomain attributes * `GET /v1/sites/123?fields[sites]=title,subdomain` Response will only include requested fields ```json { "data": { "id": "123", "type": "sites", "attributes": { "title": "Advanced Training Site", "subdomain": "advanced-training" } } } ``` tags: - Sites security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: fields[sites] in: query required: false description: Partial attributes as specified, e.g. fields[sites]=title,subdomain schema: type: string responses: '200': description: Success, shows details of a specified site content: application/vnd.api+json: schema: "$ref": "#/components/schemas/sites_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/transactions": get: summary: List transactions description: |2 List of payment transactions related to completed financial activity (successful charges, refunds, and disputes) that are associated with actual purchases, excluding test transactions, free purchases, failed attempts, and pending transactions. ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/transactions?page[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/transactions?page[number]=2&page[size]=25` The response includes pagination links and meta data: ```json { "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 } } ``` ## Sparse Fields Use the `fields[transactions]` parameter to request only specific attributes: ### Only return amount_in_cents and sales_tax_in_cents attributes * `GET /v1/transactions?fields[transactions]=amount_in_cents,sales_tax_in_cents` Response will only include requested fields ```json { "data": [{ "id": "123", "type": "transactions", "attributes": { "amount_in_cents": 9900, "sales_tax_in_cents": 990 } }] } ``` ## Filtering Use the `filter[site_id]` parameter to filter transactions by site: ### Get transactions for site with ID 123 * `GET /v1/transactions?filter[site_id]=123` Response will include only transactions for the specified site ```json { "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" } } } }] } ``` ## Date Range Filtering Use the `filter[start_date]` and `filter[end_date]` parameters to filter transactions by date range: ### Get transactions between January 1st and January 31st, 2024 * `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 ```json { "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" } } } }] } ``` ## Filtering by Name or Email Use the `filter[name_or_email]` parameter to filter transactions by name or email: ### Get transactions for customer with name or email "John" * `GET /v1/transactions?filter[name_or_email]=John` ## Filtering by Customer Use the `filter[customer_id]` parameter to filter transactions by customer: ### Get transactions for customer with ID 456789 * `GET /v1/transactions?filter[customer_id]=456789` ## Using Multiple Parameters Together You can combine multiple parameters to filter and format the response: ### Get paginated, filtered transactions with specific fields * `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: ```json { "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 } } ``` tags: - Transactions security: - Bearer: [] parameters: - name: page[number] in: query required: false schema: type: number - name: page[size] in: query required: false description: Number of documents schema: type: number - name: fields[transactions] in: query required: false description: Partial attributes as specified, e.g. fields[transactions]=amount_in_cents,sales_tax_in_cents schema: type: string - name: filter[site_id] in: query required: false description: Filter by site_id, for example ?filter[site_id]=111 schema: type: string - name: filter[customer_id] in: query required: false description: Filter by customer_id, for example ?filter[customer_id]=456789 schema: type: string - name: filter[name_or_email] in: query required: false description: Filter by name or email, for example ?filter[name_or_email]=John schema: type: string - name: filter[start_date] in: query required: false description: Filter by start_date, for example ?filter[start_date]=2024-12-01 schema: type: string - name: filter[end_date] in: query required: false description: Filter by end_date, for example ?filter[end_date]=2024-12-31 schema: type: string responses: '200': description: Success, lists transactions which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/transactions_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/transactions/{id}": get: summary: Transaction details description: |2 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. ## Transaction Attributes * `provider` (string) - The payment processor used for the payment * `action` (string) - Indicate the type of transaction: * `charge` - One-time payment * `refund` - Money returned to customer * `subscribe` - New subscription * `subscription_charge` - Recurring subscription payment * `free_purchase` - $0 transaction * `test` - Test transaction * `dispute` - Disputed charge * `subscription_update` - Subscription modification * `state` (string) - The transaction's status: * `initialized` - Transaction started * `succeeded` - Transaction completed successfully * `failed` - Transaction failed * `payment_type` (string) - Indicates the payment structure (nullable) * `amount_in_cents` (integer) - The USD price in cents (for precise decimal handling) can be negative for refunds * `sales_tax_in_cents` (integer) - The USD sales tax in cents (for precise decimal handling) * `payment_fee_in_cents` (integer) - Payment processing fee associated with the transaction (Kajabi Payments only) * `currency` (string) - String representing the currency code (nullable) automatically upcased * Defaults to "USD" if not specified * `currency_symbol` (string) - String representing the currency symbol (nullable) * Example: "$" for USD * `formatted_amount` (string) - String representing the amount in a human-readable format * Includes currency symbol * Does not include currency code * Example: "$19.99" * `settlement_amount_in_cents` (integer) - Price of the payment in cents based on the settlement currency (Kajabi Payments only) * `settlement_fee_amount_in_cents` (integer) - Payment processing fee associated with the transaction based on the settlement currency (Kajabi Payments only) * `settlement_currency` (string) - Currency of the payment based on settlement, typically the currency of the attached bank account (Kajabi Payments only) * `created_at` (string) - The creation date and time, ISO date string format (read-only) ## Sparse Fields Use the `fields[transactions]` parameter to request only specific attributes: ### Only return amount_in_cents and sales_tax_in_cents attributes * `GET /v1/transactions/123?fields[transactions]=amount_in_cents,sales_tax_in_cents` Response will only include requested fields ```json { "data": { "id": "123", "type": "transactions", "attributes": { "amount_in_cents": 9900, "sales_tax_in_cents": 990 } } } ``` ## Include Relationships Use the `include` parameter to include related resources: > **Deprecated:** the `offer` relationship is deprecated and will be removed in a future version. It is only populated for single-offer transactions and is `null` for bundled (multi-offer) transactions. Use the `purchases` relationship instead — it lists every offer purchase a transaction covers, for all transaction types. ### Include customer and purchases relationships * `GET /v1/transactions/123?include=customer,purchases` Response will include related resources ```json { "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" } }, "purchases": { "data": [ { "id": "501", "type": "purchases" } ] } } }, "included": [ { "id": "456", "type": "customers", "attributes": { "name": "John Doe", "email": "email@example.com", "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": "501", "type": "purchases", "attributes": { "amount_in_cents": 100, "payment_type": "subscription", "currency": "USD", "quantity": 1, "created_at": "2025-03-14T19:17:38.000Z", "updated_at": "2025-03-14T19:17:38.000Z" }, "relationships": { "offer": { "data": { "id": "789", "type": "offers" } } } } ] } ``` ## Using Multiple Parameters Together You can combine sparse fields and include in a single request: ### Get transaction with specific fields and included relationships * `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 ```json { "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": "john@example.com" } } ] } ``` tags: - Transactions security: - Bearer: [] parameters: - name: id in: path required: true schema: type: string - name: fields[transactions] in: query required: false description: Partial attributes as specified, e.g. fields[transactions]=amount_in_cents,sales_tax_in_cents schema: type: string - name: include in: query required: false description: Load the related resources, for example ?include=customer,purchases schema: type: string responses: '200': description: Success, shows details of a specified transaction content: application/vnd.api+json: schema: "$ref": "#/components/schemas/transactions_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '404': description: Not found, the resource is unknown content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unavailable" "/v1/version": get: summary: Version description: | 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. ## Response attributes * `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. tags: - Version responses: '200': description: Success content: application/vnd.api+json: schema: "$ref": "#/components/schemas/version_response" '503': description: Service unavailable content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unavailable" "/v1/website_pages": get: summary: List website pages description: | Returns a list of website pages which the current user may access ## Pagination Use `page[number]` and `page[size]` parameters to paginate results: ### Get first page of 10 items * `GET /v1/website_pages[number]=1&page[size]=10` ### Get second page of 25 items * `GET /v1/website_pages[number]=2&page[size]=25` ## Sorting Use the `sort` parameter to sort the results: ### Sort by created_at in ascending order * `GET /v1/website_pages?sort=created_at&fields[website_pages]=created_at` ## Filters Use the `filter[site_id]` parameter to get website pages for a specific site: ### Get website pages for site with ID 123 * `GET /v1/website_pages?filter[site_id]=123` tags: - Sites security: - Bearer: [] parameters: - name: sort in: query required: false description: 'Sort order, use: created_at for descending order use ''-'' e.g. &sort=-created_at' schema: type: string - name: page[number] in: query required: false schema: type: integer - name: page[size] in: query required: false description: Number of documents schema: type: integer - name: fields[website_pages] in: query required: false description: Partial attributes as specified, e.g. fields[website_pages]=title schema: type: string responses: '200': description: Success, list of website pages which the current user may access content: application/vnd.api+json: schema: "$ref": "#/components/schemas/website_pages_index_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" "/v1/website_pages/{id}": get: summary: Website page details description: | Details of a website page ## Website Page Attributes * `title` (string) - Title of the website page * `url` (string) - URL of the website page * `created_at` (string) - Date and time the website page was created * `updated_at` (string) - Date and time the website page was updated_at tags: - Sites security: - Bearer: [] parameters: - name: id in: path required: true description: Website page ID schema: type: string - name: fields[website_pages] in: query required: false description: Partial attributes as specified, e.g. fields[website_pages]=title schema: type: string responses: '200': description: Success, shows details of a website page content: application/vnd.api+json: schema: "$ref": "#/components/schemas/website_pages_show_response" '401': description: Unauthorized, Authorization header is missing or invalid content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_unauthorized" '403': description: Forbidden, insufficient permission to access the resource content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_forbidden" '404': description: website page not found content: application/vnd.api+json: schema: "$ref": "#/components/schemas/errors_not_found" components: securitySchemes: Bearer: type: http scheme: bearer schemas: oauth_token_response: type: object properties: access_token: type: string refresh_token: type: string token_type: type: string expires_in: type: integer blog_posts_attributes: type: object properties: title: type: string url: type: string content: type: string slug: type: string page_title: type: string page_description: type: string published_at: type: string nullable: true created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only blog_posts_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - blog_posts attributes: "$ref": "#/components/schemas/blog_posts_attributes" relationships: type: object properties: blog: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string blog_posts_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - blog_posts attributes: "$ref": "#/components/schemas/blog_posts_attributes" relationships: type: object properties: blog: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string contacts_attributes: type: object properties: name: type: string email: type: string phone_number: type: - string - 'null' business_number: type: - string - 'null' subscribed: type: boolean address_line_1: type: - string - 'null' address_line_2: type: - string - 'null' address_city: type: - string - 'null' address_state: type: - string - 'null' address_country: type: - string - 'null' external_user_id: type: string nullable: true description: Supported once contact is granted an offer or makes a purchase address_zip: type: - string - 'null' custom_1: type: string nullable: true description: Support depends on custom fields of a site custom_2: type: string nullable: true description: Support depends on custom fields of a site custom_3: type: string nullable: true description: Support depends on custom fields of a site created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only contacts_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/contacts_attributes" relationships: type: object properties: customer: type: object nullable: true properties: data: "$ref": "#/components/schemas/resource_identifier" offers: type: object nullable: true properties: links: type: object properties: self: type: string site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" tags: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: customer: type: string links: type: object properties: self: type: string current: type: string contacts_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/contacts_attributes" relationships: type: object properties: customer: type: object nullable: true properties: data: "$ref": "#/components/schemas/resource_identifier" offers: type: object nullable: true properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" tags: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: customer: type: string links: type: object properties: self: type: string current: type: string contacts_relationships_tags_response: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string contact_tags_attributes: type: object properties: name: type: string required: - name contact_tags_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/contact_tags_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string contact_tags_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/contact_tags_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string contact_notes_attributes: type: object properties: body: type: string created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only contact_notes_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - contact_notes attributes: "$ref": "#/components/schemas/contact_notes_attributes" relationships: type: object properties: contact: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string contact_notes_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - contact_notes attributes: "$ref": "#/components/schemas/contact_notes_attributes" relationships: type: object properties: contact: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string contact_notes_create_request: type: object properties: data: type: object properties: type: type: string enum: - contact_notes attributes: type: object properties: body: type: string description: The note content required: - body relationships: type: object properties: contact: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" required: - data required: - contact required: - type - attributes - relationships required: - data contact_notes_update_request: type: object properties: data: type: object properties: id: type: string type: type: string enum: - contact_notes attributes: type: object properties: body: type: string description: The note content required: - body required: - id - type - attributes required: - data custom_fields_attributes: type: object properties: title: type: string handle: type: string type: type: string required: type: boolean custom_fields_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/custom_fields_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string custom_fields_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/custom_fields_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string customers_attributes: type: object properties: name: type: string email: type: string avatar: type: - string - 'null' external_user_id: type: string nullable: true description: Supported once contact is granted an offer or makes a purchase public_bio: type: - string - 'null' public_location: type: - string - 'null' public_website: type: - string - 'null' socials: type: object nullable: true properties: twitter: type: - string - 'null' facebook: type: - string - 'null' instagram: type: - string - 'null' net_revenue: type: - string - 'null' sign_in_count: type: integer nullable: true description: Read only last_request_at: type: string nullable: true description: ISO 8601 date-time, read only bounced_at: type: string nullable: true description: ISO 8601 date-time, read only created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only customers_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/customers_attributes" relationships: type: object properties: contact: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" offers: type: object properties: links: type: object properties: self: type: string products: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: contact: type: string links: type: object properties: self: type: string current: type: string customers_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/customers_attributes" relationships: type: object properties: contact: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" offers: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string products: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: contact: type: string links: type: object properties: self: type: string current: type: string customers_relationships_offers_response: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string fields_attributes: type: object properties: title: type: - string - 'null' type: type: string required: type: boolean handle: type: string select_options: type: - string - 'null' editable: type: boolean form_attributes: type: object properties: title: type: - string - 'null' default: type: boolean webhook_url: type: object nullable: true url: type: string created_at: type: string format: date-time nullable: true readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time nullable: true readOnly: true description: ISO 8601 date-time, read only forms_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - forms attributes: "$ref": "#/components/schemas/form_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" offer: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" fields: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" forms_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - forms attributes: "$ref": "#/components/schemas/form_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" offer: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" fields: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" form_submission_attributes: type: object properties: name: type: string email: type: string phone_number: type: - string - 'null' business_number: type: - string - 'null' address_line_1: type: - string - 'null' address_line_2: type: - string - 'null' address_city: type: - string - 'null' address_state: type: - string - 'null' address_country: type: - string - 'null' address_zip: type: - string - 'null' custom_1: type: string nullable: true description: Support depends on custom fields of a site custom_2: type: string nullable: true description: Support depends on custom fields of a site custom_3: type: string nullable: true description: Support depends on custom fields of a site form_submission_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/form_submission_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" form: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string form_submissions_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/form_submission_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" form: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string form_submissions_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/form_submission_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" form: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" hooks_attributes: type: object properties: event: type: string enum: - purchase - form_submission - tag_added - tag_removed - payment_succeeded - order_created target_url: type: string created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only resource_id: type: - integer - 'null' required: - event - target_url hooks_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - hooks attributes: "$ref": "#/components/schemas/hooks_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" hooks_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - hooks attributes: "$ref": "#/components/schemas/hooks_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" landing_pages_attributes: type: object properties: title: type: string url: type: string publish_at: type: - string - 'null' created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only landing_pages_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - landing_pages attributes: "$ref": "#/components/schemas/landing_pages_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string landing_pages_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - landing_pages attributes: "$ref": "#/components/schemas/landing_pages_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string offers_attributes: type: object properties: title: type: string description: type: - string - 'null' internal_title: type: - string - 'null' currency: type: string price_in_cents: type: integer payment_type: type: string token: type: string payment_method: type: string price_description: type: string checkout_url: type: string recurring_offer: type: boolean subscription: type: boolean one_time: type: boolean single: type: boolean free: type: boolean image_url: type: - string - 'null' required: - title offers_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/offers_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" products: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string offers_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/offers_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" products: type: object properties: data: type: array items: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string courses_attributes: type: object properties: created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only title: type: string description: type: - string - 'null' thumbnail_url: type: - string - 'null' required: - title course_modules_attributes: type: object properties: title: type: string description: type: - string - 'null' position: type: - string - 'null' poster_image_url: type: - string - 'null' publishing_option: type: string course_lessons_attributes: type: object properties: title: type: string position: type: - string - 'null' status: type: string publishing_option: type: string courses_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/courses_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string courses_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/courses_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" offers: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" modules: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" lessons: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string current: type: string included: type: array items: type: object properties: id: type: string type: type: string attributes: anyOf: - "$ref": "#/components/schemas/offers_attributes" - "$ref": "#/components/schemas/courses_attributes" - "$ref": "#/components/schemas/course_modules_attributes" - "$ref": "#/components/schemas/course_lessons_attributes" relationships: type: object properties: {} orders_attributes: type: object properties: order_number: type: integer currency_code: type: string fulfilled_at: type: - string - 'null' created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only total_price_in_cents: type: integer subtotal_in_cents: type: integer sales_tax_amount_in_cents: type: integer discount_amount_in_cents: type: integer formatted_total_price: type: string formatted_subtotal: type: string currency_symbol: type: string orders_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - orders attributes: "$ref": "#/components/schemas/orders_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" customer: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" order_items: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string current: type: string orders_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - orders attributes: "$ref": "#/components/schemas/orders_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" customer: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" order_items: type: object properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string current: type: string order_items_attributes: type: object properties: quantity: type: integer currency_code: type: string item_type: type: string item_id: type: integer title: type: string fulfilled_at: type: - string - 'null' created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only total_price_in_cents: type: integer subtotal_in_cents: type: integer sales_tax_amount_in_cents: type: integer discount_amount_in_cents: type: integer formatted_total_price: type: string formatted_subtotal: type: string currency_symbol: type: string order_items_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - order_items attributes: "$ref": "#/components/schemas/order_items_attributes" relationships: type: object properties: order: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string order_items_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - order_items attributes: "$ref": "#/components/schemas/order_items_attributes" relationships: type: object properties: order: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string products_attributes: type: object properties: created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only title: type: string description: type: - string - 'null' status: type: string members_aggregate_count: type: integer product_type_name: type: string product_type_id: type: integer publish_status: type: string thumbnail_url: type: - string - 'null' url: type: - string - 'null' required: - title products_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/products_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string products_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/products_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string purchases_attributes: type: object properties: amount_in_cents: type: integer payment_type: type: string multipay_payments_made: type: - integer - 'null' opt_in: type: boolean raw_extra_contact_information: type: object currency: type: string effective_start_at: type: - string - 'null' cardholder_name: type: - string - 'null' billing_address_zip: type: - string - 'null' deactivated_at: type: - string - 'null' deactivation_reason: type: - string - 'null' coupon_code: type: - string - 'null' source: type: - string - 'null' referrer: type: - string - 'null' quantity: type: integer nullable: true created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only purchases_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - purchases attributes: "$ref": "#/components/schemas/purchases_attributes" relationships: type: object properties: offer: type: object properties: data: type: object properties: id: type: string type: type: string customer: type: object properties: data: type: object properties: id: type: string type: type: string transactions: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string products: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string links: type: object properties: self: type: string current: type: string purchases_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - purchases attributes: "$ref": "#/components/schemas/purchases_attributes" relationships: type: object properties: offer: type: object properties: data: type: object properties: id: type: string type: type: string customer: type: object properties: data: type: object properties: id: type: string type: type: string transactions: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string products: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string links: type: object properties: self: type: string current: type: string sites_attributes: type: object properties: title: type: string subdomain: type: string created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only sites_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/sites_attributes" links: type: object properties: self: type: string current: type: string sites_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/sites_attributes" links: type: object properties: self: type: string current: type: string transactions_attributes: type: object properties: action: type: string state: type: string payment_type: type: - string - 'null' amount_in_cents: type: integer sales_tax_in_cents: type: integer currency: type: string currency_symbol: type: string formatted_amount: type: string created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only transactions_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/transactions_attributes" relationships: type: object properties: customer: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" offer: type: object deprecated: true description: 'DEPRECATED: use `purchases`. Populated only for single-offer transactions; null for bundled (multi-offer) transactions.' properties: data: "$ref": "#/components/schemas/resource_identifier" purchases: type: object description: Offer purchases this transaction covers (one entry for single-offer transactions, several for bundled). properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string current: type: string transactions_show_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/transactions_attributes" relationships: type: object properties: customer: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" offer: type: object deprecated: true description: 'DEPRECATED: use `purchases`. Populated only for single-offer transactions; null for bundled (multi-offer) transactions.' properties: data: "$ref": "#/components/schemas/resource_identifier" purchases: type: object description: Offer purchases this transaction covers (one entry for single-offer transactions, several for bundled). properties: data: "$ref": "#/components/schemas/resource_identifiers" links: type: object properties: self: type: string current: type: string website_pages_attributes: type: object properties: title: type: string url: type: - string - 'null' created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only website_pages_index_response: type: object properties: data: type: array items: type: object properties: id: type: string type: type: string enum: - website_pages attributes: "$ref": "#/components/schemas/website_pages_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string website_pages_show_response: type: object properties: data: type: object properties: id: type: string type: type: string enum: - website_pages attributes: "$ref": "#/components/schemas/website_pages_attributes" relationships: type: object properties: site: type: object properties: data: "$ref": "#/components/schemas/resource_identifier" links: type: object properties: self: type: string current: type: string me_attributes: type: object properties: initials: type: string name: type: string email: type: string role_level: type: string me_response: type: object properties: data: type: object properties: id: type: string type: type: string attributes: "$ref": "#/components/schemas/me_attributes" empty_response: type: object properties: data: type: object properties: {} version_response: type: object properties: meta: type: object properties: title: type: string version: type: string links: type: object properties: documentation: type: string jsonapi: type: object properties: version: type: string specficiation: type: string resource_identifier: type: object properties: id: type: string type: type: string required: - id - type resource_identifiers: type: array items: "$ref": "#/components/schemas/resource_identifier" errors_attributes: type: object properties: status: type: string source: type: object nullable: true properties: pointer: type: string title: type: string detail: type: string errors_bad_request: type: object properties: errors: type: array items: "$ref": "#/components/schemas/errors_attributes" errors_unauthorized: type: object properties: errors: type: array items: "$ref": "#/components/schemas/errors_attributes" errors_unprocessable: type: object properties: errors: type: array items: "$ref": "#/components/schemas/errors_attributes" errors_forbidden: type: object properties: errors: type: array items: "$ref": "#/components/schemas/errors_attributes" errors_not_found: type: object properties: errors: type: array items: "$ref": "#/components/schemas/errors_attributes" errors_unavailable: type: object properties: errors: type: array items: "$ref": "#/components/schemas/errors_attributes" errors_authentication_failed: type: object properties: error: type: string podcasts_attributes: type: object properties: title: type: string description: type: string language: type: string owner_email: type: string author: type: string nullable: true status: type: string enum: - ready - importing - failed show_type: type: string enum: - episodic - serial thumbnail_url: type: string nullable: true cover_art_url: type: string nullable: true categories: type: array items: type: string directories: type: array items: type: object properties: id: type: string url: type: string config: type: object migrated_to_url: type: string nullable: true migrated: type: boolean public: type: boolean ready: type: boolean distribution_ready: type: boolean url: type: string description: Public URL for the podcast created_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only updated_at: type: string format: date-time readOnly: true description: ISO 8601 date-time, read only servers: - url: https://api.kajabi.com description: Production