Question: We want to take code we developed in Salesforce and expose it as a REST web service an external application. The external system can use either Basic Authentication or OAuth 2.0 with `grant_type=client_credentials` to authorize calls to any REST service.

I tried calling the REST endpoint in Salesforce via Basic authentication and I get `INVALID SESSION_ID` error. I also tried oAuth with `grant_type=client_credentials` and I get `unsupported_grant_type` error. ( Note: I have configured OAuth 2 using connected app in Salesforce).

I have searched the Salesforce documentation. Am I missing some configuration in Salesforce?

Answer: 
**1. SSJS**

Rows.Retrieve() loads 2500 rows at a time, and it looks like there is no option to limit the response size  

I would iterate from `0` to `target.length` to avoid `IndexOutOfBoundsException`  

But, in any way, this approach is not very effective

**1.1 SSJS + \_CustomObjectKey hack**

You can use [\_CustomObjectKey](https://developer.salesforce.com/docs/atlas.en-us.noversion.mc-programmatic-content.meta/mc-programmatic-content/claimrow.htm) in the filter as an index surrogate  

In SOAP it looks like this:

```xml
<Filter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="SimpleFilterPart">          
    <Property>_CustomObjectKey</Property>
    <SimpleOperator>greaterThan</SimpleOperator>
    <Value>42</Value>
</Filter>

```

`_CustomObjectKey` is an identity primary key - take into account that there might be gaps if some rows were deleted

You may even get several empty pages while there are lots of data starting from higher values of `_CustomObjectKey`  

You need to count all retrieved rows and check with [DataExtensionRowCount()](https://developer.salesforce.com/docs/atlas.en-us.noversion.mc-programmatic-content.meta/mc-programmatic-content/dataextensionrowcount.htm) to detect the end of the loop  

An error will lead you to the infinite loop

**2. SOAP**

Soap API [supports pagination](https://salesforce.stackexchange.com/a/321603/72249)  

You can iterate over small pages of rows.
I'm not sure that SOAP SDK's support pagination well, at least Java FuelSDK has very primitive pagination support

You can try to [use SOAP over WSProxy in SSJS](https://developer.salesforce.com/docs/atlas.en-us.mc-programmatic-content.meta/mc-programmatic-content/ssjs_WSProxy_basic_retrieve.htm)  

It should support all the advantages of SOAP

**3. REST**

You can retrieve DataExtension rows with an undocumented REST endpoint

```
GET /data/v1/customobjectdata/key/<DE-Key>/rowset

```

It supports standard [pagination and filtering](https://developer.salesforce.com/docs/atlas.en-us.noversion.mc-apis.meta/mc-apis/assetSimpleQuery.htm) parameters

You can [update DataExtension rows asynchronously](https://developer.salesforce.com/docs/atlas.en-us.noversion.mc-apis.meta/mc-apis/updateDataExtensionIDAsync.htm)  

This is a bulk update, so you just need to retrieve all rows, change data and submit upsert request for all of them
Perhaps [Denis's answer](https://salesforce.stackexchange.com/a/321788/78206) would be the normal route for a Marketing Cloud developer, so please check that out. I was hoping there was a simple filter option, but I was able to figure out a different solution by generating batch numbers on the load from the SQL statement. I'm much more comfortable with SQL than I am with JavaScript and AMPScript, so the old adage of *"use the tools you know"* applies here. I've marked this as the answer, since it solved my problem, but Denis's answer might be the "right" answer.

SQL Statement that Loads the Data Extension
-------------------------------------------

```
select
     ceiling(row_number() over(order by s.email) / 2000.0) as BatchNumber
    ,s.email as subscriber_key 
    ,'na' as pcURL
from
    Source_Data_Extension s
where
    not exists (
        select 1
        from Processed_Data_Extension e
        where e.email = s.email
    )

```

This required me to add "BatchNumber" to the data extension. The "2000.0" is the desired batch/page size. The ".0" forces SQL to treat it as a decimal instead of an int. An int value causes issues with the ceiling function. BatchNumber would start at 0 (int) instead of the desired 1 (decimal).

Updated Server-Side JavaScript
------------------------------

```
<script runat="server">
    Platform.Load("core", "1.1.1");

    var batchNumber = 1;
    var pageSize = 1;

    try{

        do {
            var targetDE = DataExtension.Init("<ExternalID>");
            var filter1 = {Property:"url_link",SimpleOperator:"equals",Value:"na"};
            var filter2 = {Property:"BatchNumber",SimpleOperator:"equals",Value: batchNumber};
            var filter = {LeftOperand: filter1, LogicalOperator: "AND", RightOperand: filter2};
            var target = targetDE.Rows.Retrieve(filter);

            pageSize = target.length;

            for (var p = 0; p < pageSize; p++)
            {    
              var subscriber_key = target[p].subscriber_key;

              var url_link = Platform.Function.TreatAsContent("%"+"%"+"=CloudPagesURL"+"(3300,'subscriber_key',\""+subscriber_key+"\")="+"%"+"%");

              var rows = Platform.Function.UpsertData("MY_DATA_EXTENSION",["subscriber_key"],[subscriber_key],["url_link"],[url_link]);
            } 

            batchNumber++;
        }
        while (pageSize > 0)
    }

    catch(e)
    {
        // log error to log data extension...
    }
</script>

```

I've added a second filter for the batch number and the do while loop continues until there are no records returned.