/// <summary>
        /// Creates a cursor to paginate large data sets.
        /// </summary>
        /// <param name="parameters">The contact list parameters used to specify the contacts and fields to include.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
        /// <returns></returns>
        public Task <ContactCursor> CreateCursorAsync(ContactListParameters parameters, CancellationToken cancellationToken = default)
        {
            Preconditions.NotNull(parameters, nameof(parameters));

            var queryParameters = new QueryParameters(
                new QueryParameter("limit", "1"),
                new QueryParameter("cursorType", "randomAccess"));

            return(PostAsync(null, queryParameters.ToString(), JsonStreamContent.Create(parameters), nameof(CreateCursorAsync), null, cancellationToken, async response =>
            {
                var headers = response.Headers;
                const string countHeaderName = "x-total-count";
                if (!headers.TryGetValues(countHeaderName, out var counts))
                {
                    throw await EncompassApiException.CreateAsync($"{nameof(CreateCursorAsync)} missing {countHeaderName} header", response).ConfigureAwait(false);
                }
                var countString = counts.First();
                if (!int.TryParse(countString, out var count) || count < 0)
                {
                    throw await EncompassApiException.CreateAsync($"{nameof(CreateCursorAsync)} invalid {countHeaderName} header value", response).ConfigureAwait(false);
                }
                string?cursorId = null;
                if (count > 0)
                {
                    const string cursorIdHeaderName = "x-cursor";
                    if (!headers.TryGetValues(cursorIdHeaderName, out var cursorIds))
                    {
                        throw await EncompassApiException.CreateAsync($"{nameof(CreateCursorAsync)} missing {cursorIdHeaderName} header", response).ConfigureAwait(false);
                    }
                    cursorId = cursorIds.First();
                }
                return new ContactCursor(this, Client, cursorId, count, parameters.Fields);
            }));
        }
        /// <inheritdoc/>
        public Task <List <ContactData> > GetContactListAsync(ContactListParameters parameters, int?start = null, int?limit = null, CancellationToken cancellationToken = default)
        {
            Preconditions.NotNull(parameters, nameof(parameters));

            var queryParameters = new QueryParameters();

            if (start.HasValue)
            {
                queryParameters.Add("start", start.ToString());
            }
            if (limit.HasValue)
            {
                queryParameters.Add("limit", limit.ToString());
            }

            return(PostAsync <List <ContactData> >(null, queryParameters.ToString(), JsonStreamContent.Create(parameters), nameof(GetContactListAsync), null, cancellationToken));
        }
 async Task <IContactCursor> IContactSelector.CreateCursorAsync(ContactListParameters parameters, CancellationToken cancellationToken) => await CreateCursorAsync(parameters, cancellationToken).ConfigureAwait(false);