> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nekt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Waid as a data source

> Bring members, access groups, courses, enrollments, progress, grades and sales from Waid (formerly Curseduca) to Nekt.

Waid (formerly Curseduca) is a Brazilian platform for online courses, members areas and course sales. This connector reads your Waid platform through its public API and brings your members and their accesses, access groups (turmas) and who belongs to each one, products (courses), lessons, enrollments with their progress, lesson completions, grades, reviews and the sales made through Waid Pay.

> [!NOTE]
>
> The connector only reads data. It never creates, changes or deletes anything in Waid.

## Configuring Waid as a Source

In the [Sources](https://app.nekt.ai/sources) tab, click on the "Add source" button located on the top right of your screen. Then, select the Waid option from the list of connectors.

Click **Next** and you'll be prompted to add your access.

### 1. Add account access

Every request to the Waid API carries two credentials: the **API Key**, which identifies your platform, and an **access token**, which identifies an administrator. You can get both in the Waid admin panel: click your name at the bottom of the left sidebar, choose **Credenciais API** and select an administrator. Only administrators, subadministrators and the developer profile can see this screen.

> [!WARNING]
>
> Waid access tokens expire after **7 days**, and clicking **Rotacionar** invalidates the previous one immediately. To avoid replacing the token every week, choose the e-mail and password sign-in: the connector then gets a fresh token on every sync.

The following configurations are available:

* **Authentication Method**: How the connector signs in.
  * **Administrator e-mail and password (recommended)**: the connector signs in as a Waid administrator on every sync and asks Waid for a token that lasts only a few hours. We recommend creating a dedicated administrator for Nekt.
  * **Access Token (expires every 7 days)**: paste the token from **Credenciais API**. You will need to replace it every week.
* **API Key**: The API Key shown in **Credenciais API**. It is the same for every administrator and does not expire.
* **Administrator E-mail** and **Administrator Password**: The administrator the connector signs in as (e-mail and password method). Use an administrator whose access is not restricted to some groups: the connector reads what this user can see. Users who only sign in with Google must set a password first, using **Forgot my password** on the Waid sign-in screen.
* **Access Token**: The token from **Credenciais API** (Access Token method).

> [!NOTE]
>
> Sign-in with e-mail and password is confirmed by Nekt on your first sync. To make it smooth:
>
> 1. Create a dedicated administrator for Nekt in Waid, with an e-mail address and a password. Users who only sign in with Google, or who have two-step verification turned on, cannot be used by an automated connection.
> 2. Fill in that e-mail (not a CPF) and password, and run the source once.
> 3. If the sign-in fails, the run log says why (wrong e-mail or password, two-step verification, CPF instead of e-mail). You can also switch to the **Access Token** method, keeping in mind that it must be replaced every 7 days.

* **Start Date**: (Optional) Earliest date to read for the streams filtered by date: members and group members (last update), lesson completions, member accesses and sales (purchase day). Leave empty to extract the whole history.
* **Lookback Days**: (Default: 1, minimum 1) Each sync also re-reads this many days before the previous sync, for members, group members, lesson completions and member accesses.
* **Sales Lookback Days**: (Default: 60, minimum 1) Waid only filters sales by purchase day, while a payment keeps changing after the purchase (confirmed, refunded, charged back). Each sync re-reads the purchases of this many past days, and also every refunded, cancelled or disputed payment bought since the Start Date (at most 400 days back).
* **Max Requests per Minute**: (Default: 120) How many requests per minute the sync may send to Waid. Waid does not publish a limit; lower it if other integrations share your API access.

Once you're done, click **Next**.

### 2. Select streams

Choose which data streams you want to sync. For faster extractions, select only the streams that are relevant to your analysis. You can select entire groups of streams or pick specific ones.

> Tip: The stream can be found more easily by typing its name.

Select the streams and click **Next**.

### 3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.

* **Layer**: choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
* **Folder**: a folder can be created inside the selected layer to group all tables being created from this new data source.
* **Table name**: we suggest a name, but feel free to customize it. You have the option to add a **prefix** to all tables at once and make this process faster!
* **Sync Type**: you can choose between INCREMENTAL and FULL\_TABLE.
  * Incremental: every time the extraction happens, we'll get only the new data, which is good if, for example, you want to keep every record ever fetched.
  * Full table: every time the extraction happens, we'll get the current state of the data, which is good if, for example, you don't want to have deleted data in your catalog.

Once you are done configuring, click **Next**.

### 4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters.

To define your [Trigger](https://docs.nekt.com/runs/scheduling-and-triggers), consider how often you want data to be extracted from this source. This decision usually depends on how frequently you need the new table data updated (every day, once a week, or only at specific times).

Optionally, you can define some additional settings:

* Configure Delta Log Retention and determine for how long we should store old states of this table as it gets updated. Read more about this resource [here](https://docs.nekt.com/get-started/core-concepts/resource-control).
* Determine when to execute an **Additional [Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync)**. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while.

Once you are ready, click **Next** to finalize the setup.

### 5. Check your new source

You can view your new source on the [Sources](https://app.nekt.ai/sources) page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.

> [!WARNING]
>
> For you to be able to see it on your [Catalog](https://app.nekt.ai/catalog), you need at least one successful source run.

# Streams and Fields

## Available streams

The table below lists every stream, its **slug** (the exact identifier to pass when creating the source via API) and a short description.

| Stream | Slug | Sync | Description |
| - | - | - | - |
| Members | `members` | Incremental | Every member of the platform (students and administrators) with contact data, status, groups and tags. |
| Member Profiles | `member_profiles` | Full table | The member report: profile fields, registration custom fields (for example state or schooling), phones, address and number of enrollments. |
| Member Accesses | `member_accesses` | Incremental | One row per access (sign-in) of a member, from the access history. |
| Access Groups | `groups` | Full table | Access groups (turmas): which products each group gives access to, how access expires and how many members it has. |
| Group Members | `group_members` | Incremental | Each member's link to each access group, including links of members removed from the group (`is_active = false`). |
| Products | `contents` | Full table | Products (courses, materials, plans) with category, type, prices, instructors and the groups that give access to them. |
| Lessons | `lessons` | Full table | Every lesson of every product, with its module and position. |
| Enrollments | `enrollments` | Full table | Every enrollment of a member in a product, with start and completion dates and the completion percentage. |
| Lesson Completions | `lesson_completions` | Incremental | One row per lesson a member finished, with the lesson, module, product, member and enrollment. |
| Member Grades | `member_grades` | Full table | Progress and average grade of each member in each product, with the minimum grade the product requires for its certificate. |
| Content Reviews | `content_reviews` | Full table | Ratings and comments members left on products and lessons. |
| Sales | `sales` | Incremental | One row per payment of Waid Pay, the platform's own checkout, with buyer, product, amounts, status and billing address. |

## Fields by stream

### Members and groups

> **Members**
>
> Every member of the platform (students and administrators) with contact data, status, groups and tags. Incremental by last update: each sync reads the members changed since the previous sync, with a one-day safety margin.
>
> Table: `members` · Primary key: `id` · Sync: Incremental (`updated_at`)
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the member (student or administrator) in Waid. |
> | `name` | String | Full name of the member. |
> | `email` | String | E-mail address of the member (unique in the platform). |
> | `document_type` | String | Type of the member's identity document (for example CPF). |
> | `document_value` | String | Number of the member's identity document. |
> | `situation` | String | Member status: ACTIVE, INACTIVE or BLOCKED. |
> | `image` | String | URL of the member's profile picture. |
> | `path` | String | Path of the member's profile picture as stored by Waid. |
> | `description` | String | Free-text description from the member's profile. |
> | `slug` | String | Slug of the member's public profile. |
> | `last_access` | Datetime | Last time the member signed in (Waid records the last login, not the last activity). |
> | `created_at` | Datetime | When the member was registered. |
> | `updated_at` | Datetime | When the member was last changed; used as the incremental replication key. |
> | `tenants` | String (JSON) | Members areas (sub-platforms) the member belongs to, as a JSON array of `{id, uuid, name, slug}`. |
> | `phone_country_code` | String | Country calling code of the member's phone. |
> | `phone_area_code` | String | Area code (DDD) of the member's phone. |
> | `phone_number` | String | Phone number of the member, without country and area code. |
> | `address_zipcode` | String | Postal code (CEP) of the member's address, as text so leading zeros are kept. |
> | `address_street` | String | Street of the member's address. |
> | `address_number` | String | Number of the member's address. |
> | `address_complement` | String | Complement of the member's address (apartment, block…). |
> | `address_neighborhood` | String | Neighborhood of the member's address. |
> | `address_city` | String | City of the member's address. |
> | `address_state` | String | State of the member's address. |
> | `address_country` | String | Country of the member's address. |
> | `groups` | String (JSON) | Access groups (classes) the member is linked to, as a JSON array of `{groupId, name}`. For the full history of each link use the group\_members stream. |
> | `tags` | String (JSON) | Tags applied to the member, as a JSON array of `{tagId, name}`. |
> | `analytics` | String (JSON) | Google Analytics client ids synced by the members area, as a JSON array of `{gaClientId, updatedAt}`. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Member Profiles**
>
> The member report: profile fields, registration custom fields (for example state or schooling), phones, address and number of enrollments. Read in full on every sync.
>
> Table: `member_profiles` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the member in Waid (same id as in the members stream). |
> | `uuid` | String | UUID of the member. |
> | `name` | String | Full name of the member. |
> | `email` | String | E-mail address of the member. |
> | `cpf` | String | CPF (Brazilian taxpayer id) of the member. |
> | `mobile_phone_country_code` | String | Country calling code of the member's mobile phone. |
> | `mobile_phone_area_code` | String | Area code (DDD) of the member's mobile phone. |
> | `mobile_phone_number` | String | Mobile phone number of the member. |
> | `landline_phone_country_code` | String | Country calling code of the member's landline. |
> | `landline_phone_area_code` | String | Area code (DDD) of the member's landline. |
> | `landline_phone_number` | String | Landline number of the member. |
> | `birth_date` | Datetime | Birth date of the member. |
> | `department` | String | Department filled in the member's profile. |
> | `profession` | String | Profession filled in the member's profile. |
> | `headline` | String | Headline shown on the member's profile. |
> | `enrollments_count` | Integer | Number of products (courses) the member is enrolled in. |
> | `schooling` | String | Schooling level filled in the member's profile. |
> | `experience` | String | Experience filled in the member's profile. |
> | `skills` | String | Skills filled in the member's profile. |
> | `hobbies` | String | Hobbies filled in the member's profile. |
> | `interests` | String | Interests filled in the member's profile. |
> | `wishes` | String | Wishes filled in the member's profile. |
> | `note` | String | Administrator's note about the member. |
> | `address_zipcode` | String | Postal code (CEP) of the member's address, as text so leading zeros are kept. |
> | `address_street` | String | Street of the member's address. |
> | `address_number` | String | Number of the member's address. |
> | `address_complement` | String | Complement of the member's address (apartment, block…). |
> | `address_neighborhood` | String | Neighborhood of the member's address. |
> | `address_city` | String | City of the member's address. |
> | `address_state` | String | State of the member's address. |
> | `groups` | String (JSON) | Access groups (classes) of the member, as a JSON array of `{id, name}`. |
> | `created_at` | Datetime | When the member was registered. |
> | `sync_at` | Datetime | Last time Waid synced the member's data. |
> | `tenants` | String (JSON) | Members areas (sub-platforms) of the member, as a JSON array of `{id, uuid, name}`. |
> | `situation` | String | Member status (ACTIVE, INACTIVE…). |
> | `tags` | String (JSON) | Tags applied to the member, as a JSON array of `{uuid, name, color}`. |
> | `fields` | String (JSON) | Custom registration fields of the member (for example state, schooling, profile), as a JSON array of `{schemaId, name, value, isAutomated}`. |
> | `ga_client_ids` | String (JSON) | Google Analytics client ids synced by the members area, as a JSON array of strings. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Member Accesses**
>
> One row per access (sign-in) of a member, from the access history. Incremental by access time.
>
> Table: `member_accesses` · Primary key: `member_id`, `accessed_at` · Sync: Incremental (`accessed_at`)
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `member_id` | Integer | Identifier of the member who accessed the platform. |
> | `member_uuid` | String | UUID of the member. |
> | `member_name` | String | Full name of the member. |
> | `member_email` | String | E-mail address of the member. |
> | `member_created_at` | Datetime | When the member was registered. |
> | `accessed_at` | Datetime | When the member accessed the platform; used as the incremental replication key. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Access Groups**
>
> Access groups (turmas): which products each group gives access to, how access expires and how many members it has. Read in full on every sync.
>
> Table: `groups` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the access group (the 'Cód' column in the Waid panel). |
> | `uuid` | String | UUID of the access group. |
> | `name` | String | Name of the access group (class). |
> | `description` | String | Description of the access group. |
> | `members_count` | Integer | Number of members linked to the group when the sync ran. |
> | `expiration_type` | String | How access expires: LIFETIME (never), RELATIVE (after an interval from enrollment) or FIXED (on a date). |
> | `expires_at` | Datetime | Date when access expires, for groups with FIXED expiration. |
> | `interval` | Integer | Length of access for groups with RELATIVE expiration, as configured in Waid. |
> | `created_at` | Datetime | When the group was created. |
> | `updated_at` | Datetime | When the group was last changed. |
> | `enable_members_board` | Boolean | Whether the members board is enabled for the group. |
> | `enable_community` | Boolean | Whether the community is enabled for the group. |
> | `term_of_use_title` | String | Title of the terms of use members of the group must accept. |
> | `term_of_use_file` | String | File (URL) of the terms of use of the group. |
> | `tenants` | String (JSON) | Members areas (sub-platforms) the group belongs to, as a JSON array of `{uuid, id, name}`. |
> | `contents` | String (JSON) | Products (courses) the group gives access to, as a JSON array of `{id, name, slug}`. |
> | `integrations` | String (JSON) | Sales integrations linked to the group, as a JSON array of `{id, name}`. |
> | `channels` | String (JSON) | Community channels linked to the group, as a JSON array of `{id, uuid, name}`. |
> | `situation` | String | Status of the group: ACTIVE or INACTIVE. |
> | `has_content_unavailable_in_tenant` | Boolean | Whether some content of the group is not available in the group's members area. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Group Members**
>
> Each member's link to each access group, including links of members removed from the group (`is_active = false`). Incremental per group by the link's last update.
>
> Table: `group_members` · Primary key: `group_id`, `member_id` · Sync: Incremental (`updated_at`)
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `group_id` | Integer | Identifier of the access group (class). |
> | `member_id` | Integer | Identifier of the member. |
> | `member_uuid` | String | UUID of the member. |
> | `name` | String | Full name of the member. |
> | `email` | String | E-mail address of the member. |
> | `entered_at` | Datetime | When the member joined the group. |
> | `expires_at` | Datetime | Expiration date set on this member's link to the group, if any. |
> | `is_active` | Boolean | Whether the link is active; false means the member was removed from the group. |
> | `inactivated_at` | Datetime | When the member was removed from the group. |
> | `updated_at` | Datetime | When the link was last changed; used as the incremental replication key. |
> | `access_expires_at` | Datetime | Effective access expiration: the link's own expiration or, when it has none, the one derived from the group's settings. Computed by Waid when the row was read. |
> | `has_access` | Boolean | Whether the member had access to the group when the row was read (active link and not expired). Expiry does not change updated\_at. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

### Learning

> **Products**
>
> Products (courses, materials, plans) with category, type, prices, instructors and the groups that give access to them. Read in full on every sync.
>
> Table: `contents` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the product (course or content) in Waid. |
> | `uuid` | String | UUID of the product. |
> | `permission` | Integer | Numeric access-permission code of the product, as returned by Waid. |
> | `situation` | Integer | Numeric status code of the product (published, draft…), as returned by Waid. |
> | `title` | String | Title of the product. |
> | `slug` | String | Slug of the product. |
> | `created_at` | Datetime | When the product was created. |
> | `updated_at` | Datetime | When the product was last changed. |
> | `tracks` | String (JSON) | Learning tracks the product belongs to, as a JSON array of `{id, name, slug}`. |
> | `images` | String (JSON) | Images of the product, as a JSON array of `{url}`. |
> | `category_id` | Integer | Identifier of the product's category. |
> | `category_name` | String | Name of the product's category. |
> | `category_slug` | String | Slug of the product's category. |
> | `category_icon` | String | Icon of the product's category. |
> | `type_id` | Integer | Identifier of the product type (course, material…). |
> | `type_name` | String | Name of the product type. |
> | `pricing` | String (JSON) | Prices of the product: single price, subscription plans and external offers, as a JSON object. |
> | `instructors` | String (JSON) | Instructors of the product, as a JSON array of `{id, name}`. |
> | `groups` | String (JSON) | Access groups that give access to the product, as a JSON array of `{id, name}`. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Lessons**
>
> Every lesson of every product, with its module and position. Read in full on every sync.
>
> Table: `lessons` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the lesson. |
> | `title` | String | Title of the lesson. |
> | `link` | String | Link (video or page) of the lesson. |
> | `lesson_order` | Integer | Position of the lesson inside its module. |
> | `section_title` | String | Title of the module (section) the lesson belongs to. |
> | `section_order` | Integer | Position of the module inside the product. |
> | `content_id` | Integer | Identifier of the product (course) the lesson belongs to. |
> | `content_title` | String | Title of the product the lesson belongs to. |
> | `content_slug` | String | Slug of the product the lesson belongs to. |
> | `quiz_config` | String (JSON) | Quiz settings of the lesson (block date, ranking), as a JSON object; null for lessons without a quiz. |
> | `created_at` | Datetime | When the lesson was created. |
> | `type_id` | Integer | Identifier of the lesson type. |
> | `type_identifier` | String | Lesson type (video, text, quiz…). |
> | `file_path` | String | File attached to the lesson, if any. |
> | `tags` | String (JSON) | Tags of the lesson, as a JSON array of `{id, title}`. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Enrollments**
>
> Every enrollment of a member in a product, with start and completion dates and the completion percentage. Read in full on every sync (Waid offers no date filter for enrollments).
>
> Table: `enrollments` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the enrollment. |
> | `content_id` | Integer | Identifier of the product (course) of the enrollment. |
> | `content_title` | String | Title of the product. |
> | `content_slug` | String | Slug of the product. |
> | `member_id` | Integer | Identifier of the member (student). |
> | `member_name` | String | Full name of the member. |
> | `member_email` | String | E-mail address of the member. |
> | `member_slug` | String | Slug of the member's public profile. |
> | `member_group_ids` | String (JSON) | Access groups of the member, as a JSON array of group ids. |
> | `started_at` | Datetime | When the member started the product. |
> | `finished_at` | Datetime | When the member completed the product; null while not completed. |
> | `situation_id` | Integer | Numeric enrollment status code (in progress, trial, cancelled, revoked…), as returned by Waid. |
> | `progress` | Number | Completion of the product by the member, in percent (0-100). |
> | `expires_at` | Datetime | When the enrollment expires, if it does. |
> | `expiration_enabled` | Boolean | Whether the enrollment has an expiration. |
> | `integration` | String | Integration (sales platform) that created the enrollment, if any. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Lesson Completions**
>
> One row per lesson a member finished, with the lesson, module, product, member and enrollment. Incremental by completion time.
>
> Table: `lesson_completions` · Primary key: `id` · Sync: Incremental (`finished_at`)
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the lesson completion. |
> | `finished_at` | Datetime | When the member finished the lesson; used as the incremental replication key. |
> | `lesson_id` | Integer | Identifier of the finished lesson. |
> | `lesson_title` | String | Title of the finished lesson. |
> | `section_id` | Integer | Identifier of the module (section) of the lesson. |
> | `section_title` | String | Title of the module of the lesson. |
> | `content_id` | Integer | Identifier of the product (course) of the lesson. |
> | `content_title` | String | Title of the product of the lesson. |
> | `content_slug` | String | Slug of the product of the lesson. |
> | `member_id` | Integer | Identifier of the member who finished the lesson. |
> | `member_email` | String | E-mail address of the member. |
> | `enrollment_id` | Integer | Identifier of the member's enrollment in the product. |
> | `enrollment_progress` | Number | Completion of the product by the member when the row was read, in percent (0-100). |
> | `group_id` | Integer | Identifier of the access group of the enrollment. |
> | `group_name` | String | Name of the access group of the enrollment. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Member Grades**
>
> Progress and average grade of each member in each product, with the minimum grade the product requires for its certificate. Read in full on every sync.
>
> Table: `member_grades` · Primary key: `member_id`, `content_id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `member_id` | Integer | Identifier of the member (student). |
> | `member_name` | String | Full name of the member. |
> | `member_email` | String | E-mail address of the member. |
> | `member_slug` | String | Slug of the member's public profile. |
> | `member_group_ids` | String (JSON) | Access groups of the member, as a JSON array of group ids. |
> | `content_id` | Integer | Identifier of the product (course). |
> | `content_uuid` | String | UUID of the product. |
> | `content_title` | String | Title of the product. |
> | `content_workload` | String | Workload (course hours) configured on the product. |
> | `content_min_grade_for_certificate` | Number | Minimum grade configured on the product to issue the certificate. |
> | `content_requires_min_grade_for_certificate` | Boolean | Whether the product requires the minimum grade to issue the certificate. |
> | `progress` | Number | Completion of the product by the member, in percent (0-100). |
> | `average_grade` | Number | Average grade of the member in the product (assessments, quizzes and graded submissions). |
> | `reached_min_grade` | Boolean | Whether the member reached the product's minimum grade. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

> **Content Reviews**
>
> Ratings and comments members left on products and lessons. Read in full on every sync.
>
> Table: `content_reviews` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | Integer | Unique identifier of the review. |
> | `rating` | String | Rating the member gave, as returned by Waid. |
> | `comment` | String | Comment the member wrote with the rating. |
> | `created_at` | Datetime | When the review was left. |
> | `member_id` | Integer | Identifier of the member (student). |
> | `member_name` | String | Full name of the member. |
> | `member_email` | String | E-mail address of the member. |
> | `member_slug` | String | Slug of the member's public profile. |
> | `content_id` | Integer | Identifier of the reviewed product (for lesson reviews, the product the lesson belongs to). |
> | `content_title` | String | Title of the product. |
> | `content_slug` | String | Slug of the product. |
> | `content_thumbnail_url` | String | Thumbnail URL of the product. |
> | `content_category` | String (JSON) | Category of the product, as a JSON object. |
> | `content_instructor` | String (JSON) | Instructor of the product, as a JSON object. |
> | `lesson_id` | Integer | Identifier of the reviewed lesson; null for product reviews. |
> | `lesson_title` | String | Title of the reviewed lesson; null for product reviews. |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

### Sales

> **Sales**
>
> One row per payment of Waid Pay, the platform's own checkout, with buyer, product, amounts, status and billing address. Incremental by purchase day: each sync re-reads the purchases of the last 60 days (**Sales Lookback Days**) and every refunded, cancelled or disputed payment bought since the Start Date (at most 400 days back).
>
> Table: `sales` · Primary key: `id_payment` · Sync: Incremental (`purchase_date`)
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id_payment` | Integer | Unique identifier of the payment. |
> | `purchase_date` | Date | Day of the purchase, taken from dt\_date\_insert; used as the incremental replication key. |
> | `ds_reference` | String | Reference code of the payment. |
> | `in_smart_installment` | Integer | 1 when the payment is a smart installment (installments by boleto or Pix), 0 otherwise; null for recurring payments. |
> | `nr_installment_count` | Integer | Number of installments. |
> | `id_paym_billing_type` | Integer | Identifier of the payment method. |
> | `billing_type_name` | String | Name of the payment method (credit card, boleto, Pix…). |
> | `id_paym_payment_type` | Integer | Identifier of the payment type. |
> | `payment_type_name` | String | Name of the payment type or gateway (for example Curseduca Pay, Hotmart, PagSeguro). |
> | `ds_bank_slip_reference` | String | Reference of the boleto (bank slip), when paid by boleto. |
> | `pr_price` | Number | Net amount of the payment (after fees), as returned by the sales report. |
> | `pr_service_fee` | Number | Service fees charged on the payment. |
> | `pr_price_gross` | Number | Gross amount of the payment (before fees). |
> | `dt_date_insert` | String | Date and time of the purchase, exactly as Waid returns it (the timezone is not documented). |
> | `dt_date_confirmed` | String | Date and time the payment was confirmed, exactly as Waid returns it. |
> | `dt_date_refund` | String | Date and time of the refund, exactly as Waid returns it; null when not refunded. |
> | `dt_date_overdue` | String | Due date of the payment (boleto/Pix), exactly as Waid returns it. |
> | `dt_date_charge` | String | Charge date of a smart-installment payment, exactly as Waid returns it. |
> | `id_paym_payment_situation` | Integer | Identifier of the payment status (3 = paid, 4 = available, 6 = refunded, 7 = cancelled…). |
> | `situation_title` | String | Name of the payment status. |
> | `id_paym_classified_origin` | Integer | Origin of the payment: 1 = single purchase, 2 = recurring, 3 = manual, 4 = cart. |
> | `is_single_payment` | Integer | 1 when the payment is a single (non-recurring) purchase, 0 otherwise. |
> | `member_id` | Integer | Identifier of the member (buyer) in Waid. |
> | `nm_name` | String | Name of the buyer. |
> | `nm_email` | String | E-mail address of the buyer. |
> | `ds_cpf` | String | CPF or CNPJ of the buyer. |
> | `ds_phone` | String | Phone of the buyer. |
> | `id_clas_classified` | Integer | Identifier of the purchased product (content) or plan. |
> | `id_clas_classified_type` | Integer | Identifier of the type of the purchased content. |
> | `nm_title` | String | Name of the purchased product or plan. |
> | `nr_quantity` | Integer | Quantity purchased. |
> | `group_id` | Integer | Identifier of the access group linked to the purchase. |
> | `group_name` | String | Name of the access group linked to the purchase. |
> | `coupon_code` | String | Discount coupon used in the purchase. |
> | `ds_credit_card` | String | Last four digits of the credit card. |
> | `ds_pix_code` | String | Pix copy-and-paste code of the payment. |
> | `ds_observation` | String | Observation recorded on the payment. |
> | `ds_postalcode` | String | Postal code (CEP) of the billing address, as text so leading zeros are kept. |
> | `ds_address` | String | Street of the billing address. |
> | `nr_address_number` | String | Number of the billing address. |
> | `ds_complement` | String | Complement of the billing address. |
> | `nm_neighborhood` | String | Neighborhood of the billing address. |
> | `nm_city` | String | City of the billing address. |
> | `nm_state` | String | State (UF) of the billing address. |
> | `nm_country` | String | Country of the billing address (Waid fills 'Brasil' by default). |
> | `extra_fields` | String (JSON) | Fields Waid returned that this connector does not map to a column (new fields, or values of an unexpected type), as a JSON object. Null when there are none. |

## Implementation Notes

### Data Quality Considerations

* **How each stream is kept up to date**:
  * Members, group members, lesson completions and member accesses: each sync reads what changed (or happened) since the previous sync, with a one-day safety margin (**Lookback Days**).
  * Sales: each sync re-reads the purchases of the last 60 days (**Sales Lookback Days**) and every payment that is refunded, cancelled or disputed among purchases since the Start Date (at most 400 days back), so those status changes reach your table even on older purchases. Other changes to purchases older than the lookback (for example a late confirmation) are picked up by a full sync.
  * Member profiles, access groups, products, lessons, enrollments, member grades and content reviews: read in full on every sync. A full read is completed before anything is loaded, so a sync that fails halfway leaves the previous table in place. Access groups are loaded completely before their members are read, so a failure while reading group members does not cut the groups table. If a stream that had records comes back completely empty, the sync stops instead of emptying the table (Content Reviews excepted: every review can be removed).
* **Removed members stay in Group Members** with `is_active = false` and the date they were removed (`inactivated_at`). `has_access` and `access_expires_at` reflect the moment the row was read: an access that simply expires does not change the link, so an incremental sync keeps the old value until a full sync.
* **Deleted records stay in incremental tables** (for example, a member deleted in Waid). A full sync removes them.
* **Nested information** (tenants, tags, prices, custom registration fields) is stored as JSON text. Small objects are split into their own columns (for example `member_id`, `content_title`, `address_city`).
* `extra_fields` keeps, as JSON, any field Waid returns that has no column of its own, and any value of an unexpected type. Fields that could give access to an account (sign-in and password links, tokens, keys, password hashes) are removed when detected by their name.
* **Sales dates** (`dt_date_insert`, `dt_date_confirmed`…) are kept exactly as Waid returns them; Waid does not document their time zone. `purchase_date` is the day of the purchase. Waid does not document whether the amounts (`pr_price`, `pr_price_gross`, `pr_service_fee`) are in reais or cents; Nekt confirms it on your first sync.
* **Sales from external checkouts** (Hotmart, Eduzz, Kiwify…) only appear if Waid records them in its sales report. For those platforms, Nekt has dedicated connectors.
* The Waid API does not provide issued certificates or detailed quiz answers. **Member Grades** shows each member's average grade and whether it reaches the minimum grade required for the certificate.
* To see every member of a group, use **Group Members**; the `groups` column of **Members** is a convenience copy.

### API Limits & Performance

* Waid does not publish a request limit. The connector sends at most 120 requests per minute (**Max Requests per Minute**) and waits when Waid asks it to slow down.
* Lists are read in pages of up to 100 records (500 for products, member grades and reviews). The connector checks every list against the total Waid reports and against the previous page. If a list changes while it is read (a student enrolls, a member is removed), the connector reads it again; if the records still do not add up to Waid's total, the sync stops and the next sync tries again. Records that Waid leaves out of both the list and its total cannot be detected.
* The first sync of a platform with many years of history reads the date-filtered streams month by month and can take a while; later syncs only read what changed.

## Troubleshooting

| Error or symptom | What it means | What to do |
| :- | :- | :- |
| "Waid rejected the API Key" | The API Key is wrong or belongs to another platform. | Copy it again from **Credenciais API** and update the source. |
| "Waid kept rejecting the access token right after signing in" | Waid refused five fresh tokens in one sync. | Check that the administrator is still active in Waid; if it is, contact Nekt support. |
| "Waid rejected the administrator e-mail or password" | The e-mail or password are wrong, or the user only signs in with Google. | Check that the user signs in to the Waid admin panel with a password, then update the source. |
| "... has two-step verification turned on" | An automated connection cannot type the verification code. | Use a dedicated administrator without two-step verification, or the Access Token method. |
| "Enter the administrator's e-mail address" | A CPF or username was filled in instead of the e-mail. | Fill in the administrator's e-mail address. |
| "Waid rejected the Access Token — Waid tokens expire after 7 days" | The token expired or was rotated. | Click **Rotacionar** in **Credenciais API**, paste the new token, or switch to e-mail and password sign-in. |
| "The Waid user of this source is not allowed to read ..." | The administrator has no access to that data (for example, a subadministrator restricted to some groups). | Use an administrator without restrictions, or deselect that stream. |
| "The ... list kept changing while it was read" | Records were added or removed during the sync many times in a row. | Run the source again. If it repeats, contact Nekt support. |
| "Waid reported N ... records but returned only M" | Waid's list and its own total disagree on every read. | Deselect the stream named in the message to keep the others running, and contact Nekt support so we can adjust it. |
| "Waid returned no ... records at all, although the previous sync read N" | A stream that had records came back empty, so the sync stopped instead of emptying the table. | If the data really was removed in Waid, run a full sync of the source to accept the empty table; otherwise deselect that stream. |
| "Waid returned a ... record whose ... cannot be read" | A record came without a readable identifier or date. | Contact Nekt support. |
| "Waid kept failing while reading ..." or "Waid did not answer ..." | The Waid API returned errors or timed out several times in a row. | Run the source again later. |
| "An access group was deleted in Waid while this sync was running" | A group disappeared between the group list and the reading of its members. | No action needed; the next sync no longer sees the group. |
| "Waid answered ... in a format this connector does not recognise" | The Waid API changed. | Contact Nekt support. |

## Skills for agents

<Snippet file="agent-skills-intro.mdx" />

> **[Download Waid skills file](/sources/waid.md)**
>
> Waid connector documentation as plain markdown, for use in AI agent contexts.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.