

# Connecting to Blackbaud Raiser's Edge NXT
<a name="connecting-to-data-blackbaud"></a>

Blackbaud Raiser's Edge NXT is a comprehensive cloud-based fundraising and donor management software solution built specifically for nonprofits and the entire social good community. This connector is built on top of Blackbaud Raiser’s Edge NXT’s SKY API and provides operations to help manage entities found within the Raisers Edge NXT.

**Topics**
+ [AWS Glue support for Blackbaud Raiser's Edge NXT](blackbaud-support.md)
+ [Policies containing the API operations for creating and using connections](blackbaud-configuring-iam-permissions.md)
+ [Configuring Blackbaud Raiser's Edge NXT](blackbaud-configuring.md)
+ [Configuring Blackbaud Raiser's Edge NXT connections](blackbaud-configuring-connections.md)
+ [Reading from Blackbaud Raiser's Edge NXT entities](blackbaud-reading-from-entities.md)
+ [Blackbaud Raiser's Edge NXT connection options](blackbaud-connection-options.md)
+ [Blackbaud Raiser's Edge NXT limitations](blackbaud-connection-limitations.md)

# AWS Glue support for Blackbaud Raiser's Edge NXT
<a name="blackbaud-support"></a>

AWS Glue supports Blackbaud Raiser's Edge NXT as follows:

**Supported as a source?**  
Yes. You can use AWS Glue ETL jobs to query data from Blackbaud Raiser's Edge NXT.

**Supported as a target?**  
No.

**Supported Blackbaud Raiser's Edge NXT API versions**  
The following Blackbaud Raiser's Edge NXT API versions are supported:
+ v1

# Policies containing the API operations for creating and using connections
<a name="blackbaud-configuring-iam-permissions"></a>

The following sample policy describes the required AWS IAM permissions for creating and using connections. If you are creating a new role, create a policy that contains the following:

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "glue:ListConnectionTypes",
        "glue:DescribeConnectionType",
        "glue:RefreshOAuth2Tokens",
        "glue:ListEntities",
        "glue:DescribeEntity"
      ],
      "Resource": "*"
    }
  ]
}
```

------

If you don't want to use the above method, alternatively use the following managed IAM policies:
+ [AWSGlueServiceRole](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole) – Grants access to resources that various AWS Glue processes require to run on your behalf. These resources include AWS Glue, Amazon S3, IAM, CloudWatch Logs, and Amazon EC2. If you follow the naming convention for resources specified in this policy, AWS Glue processes have the required permissions. This policy is typically attached to roles specified when defining crawlers, jobs, and development endpoints.
+ [AWSGlueConsoleFullAccess](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSGlueConsoleFullAccess) – Grants full access to AWS Glue resources when an identity that the policy is attached to uses the AWS Management Console. If you follow the naming convention for resources specified in this policy, users have full console capabilities. This policy is typically attached to users of the AWS Glue console.

# Configuring Blackbaud Raiser's Edge NXT
<a name="blackbaud-configuring"></a>

Before you can use AWS Glue to transfer data from Blackbaud Raiser's Edge NXT, you must meet these requirements:

## Minimum requirements
<a name="blackbaud-configuring-min-requirements"></a>

The following are minimum requirements:
+ You have a Blackbaud Raiser's Edge NXT account.
+ You have generated an Access Token in your Blackbaud Raiser's Edge NXT account with the appropriate read/write scope assigned to access the APIs. For more information, see [Authorization](https://developer.blackbaud.com/skyapi/docs/authorization).

If you meet these requirements, you’re ready to connect AWS Glue to your Blackbaud Raiser's Edge NXT account.

# Configuring Blackbaud Raiser's Edge NXT connections
<a name="blackbaud-configuring-connections"></a>

Blackbaud Raiser's Edge NXT supports the AUTHORIZATION\$1CODE grant type for OAuth2.
+ This grant type is considered "three-legged" OAuth as it relies on redirecting users to a third-party authorization server to authenticate the user. It is used when creating connections via the AWS Glue console. The AWS Glue console will redirect the user to Blackbaud Raiser's Edge NXT where the user must login and allow AWS Glue the requested permissions to access their Blackbaud Raiser's Edge NXT instance.
+ Users may opt to create their own connected app in Blackbaud Raiser's Edge NXT and provide their own Client ID, Subscription Key, and Instance URL when creating connections through the AWS Glue console. In this scenario, they will still be redirected to Blackbaud Raiser's Edge NXT to login and authorize AWS Glue to access their resources.
+ This grant type results in a refresh token and access token. The access token is short lived, and may be refreshed automatically without user interaction using the refresh token.
+ For public Blackbaud Raiser’s Edge NXT documentation on creating a connected app for Authorization Code OAuth flow, see [Authorization](https://developer.blackbaud.com/skyapi/docs/authorization).

To configure a Blackbaud Raiser's Edge NXT connection:

1. In AWS Secrets Manager, create a secret with the following details:

   1. For the customer managed connected app, the Secret should contain the connected app API key with `USER_MANAGED_CLIENT_APPLICATION_CLIENT_SECRET` as key.

   1. Note: you must create a secret for your connections in AWS Glue.

1. In AWS Glue Glue Studio, create a connection under **Data Connections** by following the steps below:

   1. When selecting a **Data Source**, select Blackbaud Raiser's Edge NXT.

   1. Provide the `INSTANCE_URL` of the Blackbaud Raiser's Edge NXT account you want to connect to.

   1. Provide the user managed client application `clientId`.

   1. Provide the subscription key associated with your account.

   1. Select the AWS IAM role which AWS Glue can assume and has permissions for following actions:

------
#### [ JSON ]

****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "secretsmanager:DescribeSecret",
              "secretsmanager:GetSecretValue",
              "secretsmanager:PutSecretValue",
              "ec2:CreateNetworkInterface",
              "ec2:DescribeNetworkInterfaces",
              "ec2:DeleteNetworkInterface"
            ],
            "Resource": "*"
          }
        ]
      }
      ```

------

   1. Select the `secretName` which you want to use for this connection in AWS Glue to put the tokens.

   1. Select the network options if you want to use your network.

1. Grant the IAM role associated with your AWS Glue job permission to read `secretName`.

# Reading from Blackbaud Raiser's Edge NXT entities
<a name="blackbaud-reading-from-entities"></a>

**Prerequisite**

A Blackbaud Raiser's Edge NXT object you would like to read from. You will need the object name.

**Supported entities for source**:


| Entity | Can be filtered | Supports limit | Supports Order by | Supports Select \$1 | Supports partitioning | 
| --- | --- | --- | --- | --- | --- | 
| Constituent Address | Yes | Yes | No | Yes | Yes | 
| Constituent Education | Yes | Yes | No | Yes | Yes | 
| Constituent Email address | Yes | Yes | No | Yes | Yes | 
| Constituent Phone | Yes | Yes | No | Yes | Yes | 
| Constituent Note | Yes | Yes | No | Yes | Yes | 
| Constituent Relationship | Yes | Yes | No | Yes | Yes | 
| Constituent Online presence | Yes | Yes | No | Yes | Yes | 
| Opportunity | Yes | Yes | No | Yes | Yes | 
| Appeal | Yes | Yes | No | Yes | Yes | 
| Campaign | Yes | Yes | No | Yes | Yes | 
| Fund | Yes | Yes | No | Yes | Yes | 
| Package | Yes | Yes | No | Yes | Yes | 
| Gift Batch | Yes | Yes | No | Yes | No | 
| Event Participant | Yes | Yes | Yes | Yes | Yes | 
| Constituent Fundraiser Assignment | No | No | No | Yes | No | 
| Gift | Yes | Yes | Yes | Yes | Yes | 
| Membership | Yes | Yes | No | Yes | Yes | 
| Action | Yes | Yes | No | Yes | No | 
| Constituent | Yes | Yes | Yes | Yes | Yes | 
| Constituent Goods | Yes | Yes | No | Yes | Yes | 
| Event | Yes | Yes | Yes | Yes | Yes | 
| Gift custom field | Yes | Yes | No | Yes | Yes | 

**Example**:

```
blackbaud_read = glueContext.create_dynamic_frame.from_options(
    connection_type="BLACKBAUD",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "API_VERSION": "v1",
        "SUBSCRIPTION_KEY": <Subscription key associated with one's developer account>
    }
```

## Blackbaud Raiser's Edge NXT entity and field details
<a name="blackbaud-reading-entity-field-details"></a>

For more information about the entities and field details see:
+ [Action](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Action)
+ [Constituent](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Constituent)
+ [Constituent Address](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Address)
+ [Constituent Membership](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Membership)
+ [Constituent Fundraiser Assignment](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#FundraiserAssignment)
+ [Constituent Education](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Education)
+ [Constituent Email Address](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#EmailAddress)
+ [Constituent Phone](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Phone)
+ [Constituent Note](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Note)
+ [Constituent Online Presence](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#OnlinePresence)
+ [Constituent Relationship](https://developer.blackbaud.com/skyapi/renxt/constituent/entities#Relationship)
+ [Event](https://developer.blackbaud.com/skyapi/renxt/event/entities#Event)
+ [Event Participant](https://developer.blackbaud.com/skyapi/renxt/event/entities#Participant)
+ [Appeal](https://developer.blackbaud.com/skyapi/renxt/fundraising/entities#Appeal)
+ [Campaign](https://developer.blackbaud.com/skyapi/renxt/fundraising/entities#Campaign)
+ [Fund](https://developer.blackbaud.com/skyapi/renxt/fundraising/entities#Fund)
+ [Package](https://developer.blackbaud.com/skyapi/renxt/fundraising/entities#Package)
+ [Gift](https://developer.blackbaud.com/skyapi/renxt/gift/entities#Gift)
+ [Gift Custom Field](https://developer.blackbaud.com/skyapi/renxt/gift/entities#CustomField)
+ [Gift Batch](https://developer.blackbaud.com/skyapi/renxt/gift-batch/entities#GiftBatch)
+ [Opportunity](https://developer.blackbaud.com/skyapi/renxt/opportunity/entities#Opportunity)
+ [Constituent Codes](https://developer.sky.blackbaud.com/api#api=56b76470069a0509c8f1c5b3)

**Note**  
Struct and List data types are converted to String data type, and DateTime data type is converted to Timestamp in the response of the connectors.

## Partitioning queries
<a name="blackbaud-reading-partitioning-queries"></a>

**Field-based partitioning**:

Blackbaud Raiser's Edge NXT doesn’t support field based or record based partitioning.

**Record-based partitioning**:

You can provide the additional Spark option `NUM_PARTITIONS` if you want to utilize concurrency in Spark. With this parameter, the original query would be split into `NUM_PARTITIONS` number of sub-queries that can be executed by Spark tasks concurrently.

In record based partitioning, the total number of records present is queried from Blackbaud Raiser’s Edge NXT API, and it is divided by `NUM_PARTITIONS` number provided. The resulting number of records are then concurrently fetched by each sub-query.
+ `NUM_PARTITIONS`: the number of partitions.

Example:

```
blackbaud_read = glueContext.create_dynamic_frame.from_options(
    connection_type="BLACKBAUD",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "API_VERSION": "v1",
        "NUM_PARTITIONS": "2",
        "SUBSCRIPTION_KEY": <Subscription key associated with one's developer account>
    }
```

# Blackbaud Raiser's Edge NXT connection options
<a name="blackbaud-connection-options"></a>

The following are connection options for Blackbaud Raiser's Edge NXT:
+ `ENTITY_NAME`(String) - (Required) Used for Read. The name of your object in Blackbaud Raiser's Edge NXT.
+ `API_VERSION`(String) - (Required) Used for Read. Blackbaud Raiser's Edge NXT Rest API version you want to use.
+ `SELECTED_FIELDS`(List<String>) - Default: empty(SELECT \$1). Used for Read. Columns you want to select for the object.
+ `FILTER_PREDICATE`(String) - Default: empty. Used for Read. It should be in the Spark SQL format.
+ `QUERY`(String) - Default: empty. Used for Read. Full Spark SQL query.
+ `NUM_PARTITIONS`(Integer) - Default: 1. Used for Read. Number of partitions for read. Example value: 10.
+ `SUBSCRIPTION_KEY`(String) - (Required) Default: empty. Used for Read. Subscription key associated with one's developer account.

# Blackbaud Raiser's Edge NXT limitations
<a name="blackbaud-connection-limitations"></a>

The following are limitations or notes for Blackbaud Raiser's Edge NXT:
+ The SaaS only supports the `EQUAL_TO` operator, which returns results created or modified on or after the specified date. Additionally, the "id" field is a String data type. There is also no identification of non-nullable fields. Therefore, field-based partitioning is not supported.
+ Incremental pull is only supported by the `Event` entity with daily, monthly and weekly frequencies.
+ The Constituent Fundraiser Assignment entity returns a maximum of 20 records.
+ Record-based partitioning:
  + Not supported by the `Action`, `Constituent Fundraiser Assignment` or `Gift Batch` entities.
  + Record-based partitioning with the filter predicate is only supported by the `Event` and `Event Participant` entities. If a filter predicate is used with any other record-based supported entities, an exception will be thrown.
+ In the `Gift Custom Field` entity, the field 'value' must be used in conjunction with the field 'category', which otherwise leads to an unfiltered response. Thus, to compel the user to plug in the 'category' field while filtering with the 'value' field, an exception will be thrown if the aforementioned requirement has not been followed.
+ The `date_added` and `last_modified` fields for all applicable entities do not support any comparative operators. They only support the equal to operator. Also, there is no field that can be paired with the aforementioned fields to provide a range of records. Hence, these fields are only queryable and cannot support incremental transfer.
+ The `added_by` field in the `Gift Batch` entity will not be considered as filterable as it might not emit the correct results.
+ There is a latency of approximately 30 minutes for records to be retrieved via the `/GET Gift List` endpoint upon insertion of data in the `Gift` entity.
+ Support for incremental transfer has been dropped for the Gift entity due to limitations from the data source's end. 
+ There exists a 10 minute latency for the status field in the Opportunity entity.
+ The `Fundraiser Assignment` entity has `Constituent` as the dependent entity. The connector loads at most 5,000 IDs to choose from, to avoid the response size exceeding the maximum allowed payload size.