> ## 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.

# RingCentral as a data source

> Bring your company call log, users, phone numbers, call queues and messages from RingCentral to Nekt.

RingCentral is a cloud phone system (RingEX) for calls, SMS, voicemail and fax. This connector reads your RingCentral account through the RingCentral REST API and brings the **company call log** (every inbound and outbound call of every user, with its result, duration, recording link, cost and the detailed legs of transfers and forwards), the account directory (users and other extensions, company phone numbers, call queues and their members) and the **messages** of every mailbox (SMS, MMS, voicemail and fax).

> [!NOTE]
>
> The connector only reads data. It never places calls, sends messages, or changes anything in RingCentral, and it does not download recordings, voicemail audio, or fax documents (only their links).

> [!WARNING]
>
> **Do not run a Full sync or an Additional Full Sync on Call Log or Messages.** RingCentral keeps call history and messages only for a limited time (see its data retention policy), so a full sync replaces everything Nekt has accumulated in these two tables with what RingCentral still keeps. Keep these two tables on incremental syncs.

## Configuring RingCentral 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 RingCentral option from the list of connectors.

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

### 1. Add account access

The connector signs in with a **JWT credential** of a RingCentral user, presented to a RingCentral app that you create in your own account. Nekt does not need any app of its own.

**1. Create the app**

Sign in to the [RingCentral Developer Console](https://developers.ringcentral.com/my-account.html) with your RingCentral account and open **Apps > Create App**. Choose **REST API App**, select the **JWT auth flow** authentication, and add the permissions **Read Call Log**, **Read Accounts**, and **Read Messages** (you can leave out Read Messages if you will not sync Messages). Save the app.

**2. Copy the app credentials**

In the app, open **Credentials** and copy the **Client ID** and the **Client Secret**.

**3. Create the JWT credential**

Signed in as a user with the **Super Admin** role (or another role that can see the company call log, users, phone numbers, and messages), click your name in the top-right corner, open **Credentials**, and click **Create JWT**. Allow it for the app you created and copy the JWT. A dedicated service user is recommended, so the source keeps working when people leave the company.

See RingCentral's guides on [JWT authentication](https://developers.ringcentral.com/guide/authentication/jwt-flow) and [creating a JWT credential](https://developers.ringcentral.com/guide/getting-started/create-credential).

The following configurations are available:

* **Client ID**: The Client ID of your RingCentral app.
* **Client Secret**: The Client Secret of your RingCentral app.
* **JWT Credential**: The JWT credential of the RingCentral admin user, allowed for the app.
* **Start Date**: The earliest date of the Call Log and Messages read on the first sync and on full syncs. The other tables are always read in full.
* **RingCentral Server** (advanced): Keep `https://platform.ringcentral.com` unless your service is AT\&T Office\@Hand or Verizon, which use `https://platform.ringcentral.biz`.
* **Lookback (days)** (advanced): Each sync reads Call Log and Messages again from this many days before the previous sync, to pick up calls that ended later and records RingCentral completes afterwards (recordings, read status). From 1 to 30; default: 2.

> [!NOTE]
>
> RingCentral limits how many requests an app may send per user and per minute (for the call log, 10 per minute by default). The **first sync** (and any full sync) reads the whole period from the Start Date in one go: for a busy account and a Start Date a year back this can take many hours, so pick the Start Date you really need. Later syncs read only the recent days; if a source falls far behind, each sync stops after a few hours, keeps what it read, and the next one continues. The limit is shared with anything else that uses the same app and JWT credential, so use them only for Nekt.

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.

> [!WARNING]
>
> Keep **Call Log** and **Messages** on **Incremental**. As Full table they would hold only what RingCentral still keeps.

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.md), 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. **Do not enable it for Call Log or Messages** (see the warnings above).

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.

## Permissions per table

If the app or the JWT user lacks a permission, the tables that need it are skipped (and named in the sync log, with the permission to grant) while the other tables keep syncing.

| Table | App permission | What the JWT user needs |
| - | - | - |
| Call Log | Read Call Log | A role that can see the whole company call log (for example Super Admin) |
| Extensions, Call Queues, Call Queue Members | Read Accounts | A role that can view users and extensions |
| Phone Numbers | Read Accounts | A role that can view company phone numbers |
| Messages | Read Messages (and Read Accounts) | A role that can read the users' messages |

# 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 |
| - | - | - | - |
| Call Log | `call_log` | Incremental | Every call of the company: caller, callee, result, duration, recording link, cost and the detailed legs. |
| Extensions | `extensions` | Full table | Users and every other extension (call queues, IVR menus, voicemail-only...) with contact details, site and status. |
| Phone Numbers | `phone_numbers` | Full table | Company and direct phone numbers and the extension each one is assigned to. |
| Call Queues | `call_queues` | Full table | Call queues (call groups) of the account. |
| Call Queue Members | `call_queue_members` | Full table | Which extensions are members of each call queue. |
| Messages | `messages` | Incremental | SMS, MMS, voicemail, fax, and pager messages of every mailbox. |

> [!NOTE]
>
> Nested information (call legs, transfers, message recipients and attachments, permissions, addresses) comes as JSON text. Fields RingCentral returns that have no column of their own are kept in `extra_fields` (JSON text). Analytics reports, RingCentral Video, and Contact Center data are not included.

## Fields by stream

> [accordion] Call Log
>
> Every call of every extension of the account, from the company call log with the detailed view (one row per call, with its legs). Read incrementally by the call's start time: each sync reads again from the previous sync minus the lookback, because a call only appears once it is over.
>
> Table: `call_log` · Primary key: `id` · Sync: Incremental (`start_time`)
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Internal identifier of the call log record. |
> | `uri` | String | Canonical URI of the call log record. |
> | `session_id` | String | Internal identifier of the call session; records of the same call share it. |
> | `telephony_session_id` | String | Telephony identifier of the call session. |
> | `sip_uuid_info` | String | Call session identifier used by the Telephony API. |
> | `party_id` | String | Internal identifier of the participant. |
> | `start_time` | Datetime | When the call started (UTC), used as the incremental replication key. |
> | `duration` | Integer | Call duration in seconds. |
> | `duration_ms` | Integer | Call duration in milliseconds. |
> | `type` | String | Call type: Voice or Fax. |
> | `direction` | String | Call direction: Inbound or Outbound. |
> | `action` | String | Call action (Phone Call, VoIP Call, Transfer, FindMe, RingOut...). |
> | `result` | String | Call result (Accepted, Missed, Voicemail, Call connected, Busy...). |
> | `reason` | String | Reason of the call result. |
> | `reason_description` | String | Detailed description of the call result reason. |
> | `internal_type` | String | Internal call type (Local, LongDistance, International, Sip...). |
> | `transport` | String | Call transport: PSTN or VoIP. |
> | `from_phone_number` | String | Phone number of the caller, as RingCentral returns it. |
> | `from_extension_number` | String | Short extension number of the caller, when the party is an extension of the account. |
> | `from_extension_id` | String | Internal identifier of the caller's extension, when the party is an extension of the account. |
> | `from_name` | String | Name associated with the caller (extension or caller ID name). |
> | `from_location` | String | Location (city, state) of the caller, when it can be determined from the phone number. |
> | `from_device_id` | String | Internal identifier of the caller's device. |
> | `from_dialer_phone_number` | String | Phone number the caller dialed from, without format changes (inbound calls). |
> | `to_phone_number` | String | Phone number of the callee, as RingCentral returns it. |
> | `to_extension_number` | String | Short extension number of the callee, when the party is an extension of the account. |
> | `to_extension_id` | String | Internal identifier of the callee's extension, when the party is an extension of the account. |
> | `to_name` | String | Name associated with the callee (extension or caller ID name). |
> | `to_location` | String | Location (city, state) of the callee, when it can be determined from the phone number. |
> | `to_device_id` | String | Internal identifier of the callee's device. |
> | `to_dialed_phone_number` | String | Phone number dialed, without format changes (outbound calls). |
> | `extension_id` | String | Internal identifier of the extension the record belongs to. |
> | `extension_uri` | String | Canonical URI of the extension the record belongs to. |
> | `delegate_id` | String | Internal identifier of the secretary extension, for calls handled on behalf of someone. |
> | `delegate_name` | String | Name of the secretary extension. |
> | `delegation_type` | String | Delegation type (Coworker, Unknown). |
> | `recording_id` | String | Internal identifier of the call recording, when the call was recorded. |
> | `recording_type` | String | Recording mode: Automatic or OnDemand. |
> | `recording_uri` | String | Link to the call recording metadata. |
> | `recording_content_uri` | String | Link to the recording audio (requires an authorized RingCentral request). |
> | `short_recording` | Boolean | True when the recording is too short to be returned. |
> | `message_id` | String | Internal identifier of the message linked to the call (for example the voicemail left). |
> | `message_type` | String | Type of the message linked to the call. |
> | `message_uri` | String | Link to the message linked to the call. |
> | `billing_cost_included` | Number | Cost per minute already included in the RingCentral service plan. |
> | `billing_cost_purchased` | Number | Cost per minute paid and not included in the RingCentral service plan. |
> | `transfer_target` | String | Transfer target of the call, when it was transferred (JSON text). |
> | `transferee` | String | Transferee of the call, when it was transferred (JSON text). |
> | `legs` | String | Legs of the call (each forward, transfer or ring of the call), as RingCentral details them (JSON text). |
> | `deleted` | Boolean | True when the record was deleted. |
> | `last_modified_time` | Datetime | When RingCentral last modified the record. |
> | `extra_fields` | String | Fields RingCentral returned that this connector does not map to a column yet, keyed by their original names (JSON text). |

> [accordion] Extensions
>
> Users and every other extension of the account (call queues appear with type `Department`, as RingCentral names them). Read in full on every sync.
>
> Table: `extensions` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Internal identifier of the extension. |
> | `uri` | String | Canonical URI of the extension. |
> | `extension_number` | String | Short extension number. |
> | `name` | String | Extension name (first and last name for users). |
> | `type` | String | Extension type (User, Department = call queue, IvrMenu, Announcement, Voicemail, SharedLinesGroup...). |
> | `sub_type` | String | Extension subtype, when applicable. |
> | `status` | String | Extension status (Enabled, Disabled, Frozen, NotActivated, Unassigned). |
> | `hidden` | Boolean | True when the extension is hidden from the company directory. |
> | `contact_first_name` | String | User's first name. |
> | `contact_last_name` | String | User's last name. |
> | `contact_company` | String | User's company name. |
> | `contact_job_title` | String | User's job title. |
> | `contact_email` | String | User's contact email. |
> | `contact_business_phone` | String | User's business phone number (E.164). |
> | `contact_mobile_phone` | String | User's mobile phone number (E.164). |
> | `contact_department` | String | User's department name. |
> | `contact_email_as_login_name` | Boolean | True when the contact email is also the login name. |
> | `contact_business_address` | String | User's business address (JSON text). |
> | `contact_pronounced_name` | String | How the user's name is pronounced (JSON text). |
> | `site_id` | String | Internal identifier of the site the extension belongs to. |
> | `site_name` | String | Name of the site the extension belongs to. |
> | `site_code` | String | Code of the site the extension belongs to. |
> | `assigned_country_iso_code` | String | ISO code of the country assigned to the user. |
> | `assigned_country_name` | String | Name of the country assigned to the user. |
> | `cost_center_id` | String | Internal identifier of the cost center. |
> | `cost_center_name` | String | Name of the cost center. |
> | `call_queue_info` | String | Service level settings, for call queue extensions (JSON text). |
> | `permissions` | String | Extension permissions (admin, international calling) (JSON text). |
> | `profile_image` | String | Profile image information (JSON text). |
> | `extra_fields` | String | Fields RingCentral returned that this connector does not map to a column yet, keyed by their original names (JSON text). |

> [accordion] Phone Numbers
>
> Phone numbers of the account, company-level and direct numbers. Read in full on every sync.
>
> Table: `phone_numbers` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Internal identifier of the phone number. |
> | `uri` | String | Canonical URI of the phone number. |
> | `phone_number` | String | Phone number (E.164). |
> | `label` | String | Custom name of the phone number, if any. |
> | `location` | String | Location (city, state) of the number. |
> | `payment_type` | String | Payment type (Local, TollFree, External...). |
> | `status` | String | Status of the number (Normal, Pending, PortedIn, Temporary). |
> | `type` | String | Number type (VoiceFax, FaxOnly, VoiceOnly). |
> | `usage_type` | String | Usage of the number (MainCompanyNumber, CompanyNumber, DirectNumber, ConferencingNumber...). |
> | `primary` | Boolean | True when the number is the primary (main) number. |
> | `vanity_pattern` | String | Vanity pattern of the number, when it has one. |
> | `country_id` | String | Internal identifier of the number's country. |
> | `country_name` | String | Name of the number's country. |
> | `extension_id` | String | Internal identifier of the extension the number is assigned to. |
> | `extension_name` | String | Name of the extension the number is assigned to. |
> | `extension_number` | String | Short number of the extension the number is assigned to. |
> | `temporary_number` | String | Temporary number, for numbers being ported in (JSON text). |
> | `contact_center_provider` | String | Contact center routing provider of the number (JSON text). |
> | `features` | String | Features enabled on the number (JSON text). |
> | `extra_fields` | String | Fields RingCentral returned that this connector does not map to a column yet, keyed by their original names (JSON text). |

> [accordion] Call Queues
>
> Call queues of the account. Read in full on every sync.
>
> Table: `call_queues` · Primary key: `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Internal identifier of the call queue (its extension id). |
> | `uri` | String | Canonical URI of the call queue. |
> | `extension_number` | String | Extension number of the call queue. |
> | `name` | String | Name of the call queue. |
> | `status` | String | Call queue status (Enabled, Disabled, NotActivated). |
> | `sub_type` | String | Call queue subtype (Emergency), when applicable. |
> | `extra_fields` | String | Fields RingCentral returned that this connector does not map to a column yet, keyed by their original names (JSON text). |

> [accordion] Call Queue Members
>
> One row per member of each call queue. Read in full on every sync.
>
> Table: `call_queue_members` · Primary key: `call_queue_id`, `id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `call_queue_id` | String | Internal identifier of the call queue. |
> | `id` | String | Internal identifier of the member's extension. |
> | `uri` | String | Canonical URI of the member. |
> | `extension_number` | String | Extension number of the member. |
> | `extra_fields` | String | Fields RingCentral returned that this connector does not map to a column yet, keyed by their original names (JSON text). |

> [accordion] Messages
>
> Messages of every mailbox: users, call queues, voicemail-only, and fax extensions that are enabled or disabled. Read incrementally by creation time, each mailbox from its own previous sync minus the lookback; a mailbox added later starts at the Start Date. Extensions that RingCentral says have no message store are skipped. Mailboxes RingCentral does not let the JWT user read (for example when the user's admin role is limited to some sites) are skipped with a warning in the sync log; a few of them are retried at the start of every sync, so they are read again once the permission is fixed; when most mailboxes are refused, the Messages table fails with a message asking for a Super Admin JWT user.
>
> Table: `messages` · Primary key: `mailbox_extension_id`, `id` · Sync: Incremental (`creation_time`)
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `mailbox_extension_id` | String | Internal identifier of the extension whose mailbox holds the message. |
> | `id` | String | Internal identifier of the message. |
> | `uri` | String | Canonical URI of the message. |
> | `extension_id` | String | Internal identifier of the extension the message belongs to, as RingCentral returns it. |
> | `type` | String | Message type (SMS, VoiceMail, Fax, Pager, Text). |
> | `direction` | String | Message direction: Inbound or Outbound. |
> | `creation_time` | Datetime | When the message was created (UTC), used as the incremental replication key. |
> | `last_modified_time` | Datetime | When the message was last modified in RingCentral (read status, availability...). |
> | `subject` | String | Message subject; for SMS and pager messages, the message text. |
> | `message_status` | String | Message status (Queued, Sent, Delivered, DeliveryFailed, SendingFailed, Received). |
> | `read_status` | String | Read status: Read or Unread. |
> | `availability` | String | Availability: Alive, Deleted (can be restored) or Purged. |
> | `priority` | String | Message priority: Normal or High. |
> | `conversation_id` | String | Conversation the message belongs to (SMS and pager). |
> | `from_phone_number` | String | Sender's phone number. |
> | `from_extension_number` | String | Sender's short extension number, when internal. |
> | `from_extension_id` | String | Sender's extension identifier, when internal. |
> | `from_name` | String | Sender's name. |
> | `from_location` | String | Sender's location (city, state), when known. |
> | `to` | String | Recipients of the message, with their delivery status (JSON text). |
> | `attachments` | String | Attachments of the message (audio, transcription, text, documents) with their content links (JSON text). |
> | `delivery_error_code` | String | SMS delivery error code returned by the gateway. |
> | `sms_delivery_time` | Datetime | When an outbound SMS was delivered to the recipient's handset. |
> | `sms_sending_attempts_count` | Integer | Number of attempts to send an outbound SMS. |
> | `vm_transcription_status` | String | Status of the voicemail-to-text transcription. |
> | `fax_page_count` | Integer | Number of pages of a fax. |
> | `fax_resolution` | String | Fax resolution: High or Low. |
> | `cover_index` | Integer | Fax cover page identifier (0 = no cover page). |
> | `cover_page_text` | String | Fax cover page text. |
> | `pg_to_department` | Boolean | Pager messages: true when a recipient is a call queue. |
> | `extra_fields` | String | Fields RingCentral returned that this connector does not map to a column yet, keyed by their original names (JSON text). |

## Implementation notes

* **Call history retention**: RingCentral deletes old call log records, recordings (from 90 days), and messages according to its data retention policy. Keep the source syncing regularly so the history builds up in Nekt, and do not run full syncs on Call Log or Messages.
* **A table that suddenly comes back empty**: if Extensions, Phone Numbers, Call Queues, or Call Queue Members return no rows after previous syncs had some, the connector reads them again and empties the table only when RingCentral confirms it has none. Otherwise that table fails without being emptied and the sync log asks you to reset only that table. Do not run a full sync of the whole source for this.
* **Start Date too old**: if RingCentral refuses the Start Date because it is older than the history it keeps, the sync log says so; set a more recent Start Date.
* **Changes after the lookback**: a call or message changed in RingCentral more than **Lookback (days)** after the previous sync is not read again. Increase the lookback if your team edits records later.
* **Rate limits**: requests are paced under RingCentral's per-minute limits; when RingCentral asks to slow down, the sync waits and the sync log says so.


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