Improve your Skyline experience
You're using a browser that skyline.benevity.org does not support. Try Chrome, Edge, Safari or Firefox for a better experience.

# Make a Bulk Donation

The Bulk Donation endpoint provides the ability to create thousands of donations at once for an integration where batching transactions would be optimal over single serial transactions. To optimize the operation further, the endpoint accepts a compressed file of donation objects that will be processed asynchronously in the background.

Currently bulk donations are only available for postpaid donations, and after your file is uploaded, the donations may take up to 24 hours to be processed. You will be able to check the status of your donations throughout the process to receive updates.

# Bulk File Format

Your file must be a properly formatted json object, and provided as a compressed .gz file. The file that you provide does not have to conform to a specific naming convention, but you should restrict the usage of special characters for its name. In the file, data must be present as the only top level attribute, which should be an array of donations. Each individual donation in the array follows the same rules you would use for Creating a Donation.

# Example Bulk File:

{
	"data": [
		{
			"type": "donations",
			"attributes": {
				"donor": {
					"receipted": true,
					"fullName": "Benevity User 1",
					"email": "test@benevity.com",
					"address": {
						"city": "Calgary",
						"country": "CA",
						"line1": "5555 Calgary St",
						"line2": "Suite 101",
						"state": "AB",
						"zip": "T0A 1B2"
					}
				},
				"destination": {
					"recipientId": "124-119219814RR0001",
					"foundationId": "1XABCDE4UT"
				},
				"funds": {
					"amount": 111,
					"currencyCode": "CAD",
					"paymentType": "DONATION_REPORT",
					"source": "COMPANY"
				},
				"metadata": {
					"vendor-id": "abc-12382",
					"location": "NW Calgary",
					"refill_date": "05/15/2023"
				}
			}
		},
		{
			"type": "donations",
			"attributes": {
				"donor": {
					"receipted": true,
					"fullName": "Benevity User 2",
					"email": "test@benevity.com",
					"address": {
						"city": "Calgary",
						"country": "CA",
						"line1": "5555 Calgary St",
						"line2": "Suite 101",
						"state": "AB",
						"zip": "T0A 1B2"
					}
				},
				"destination": {
					"recipientId": "124-119219814RR0001",
					"foundationId": "1XABCDE4UT"
				},
				"funds": {
					"amount": 222,
					"currencyCode": "CAD",
					"paymentType": "DONATION_REPORT",
					"source": "COMPANY"
				},
				"metadata": {
					"key1": "value1",
					"key 2": "value 2"
				}
			}
		},
		{
			"type": "donations",
			"attributes": {
				"destination": {
					"recipientId": "124-119219814RR0001",
					"foundationId": "1XABCDE4UT"
				},
				"funds": {
					"amount": 333,
					"currencyCode": "CAD",
					"paymentType": "DONATION_REPORT",
					"source": "COMPANY"
				},
				"metadata": {}
			}
		}
	]
}

# Create a Bulk Intent

Bulk Intents guide you through the process of uploading thousands of donations at a single time. Upon creation, your Bulk Intent will provide the necessary fields for you to complete your file upload, along with the required identifiers for you to track your donations later.

To begin, you must first invoke the POST /donations/bulk-intents endpoint to create your Bulk Intent, which will in turn provide you with a presigned URL for a file upload, along with the other required fields.

# Sample Request:

# Sample Response:

{
  "data": {
    "type": "bulkDonationIntent",
    "id": "f1c1aa80-cd86-422e-acf6-7a5330e26b1e",
    "attributes": {
      "status": "PENDING",
      "createdAt": "2021-08-03T15:27:28.531Z",
      "expiresAt": "2021-08-03T15:37:28.531Z",
      "url": "https://s3.us-east-1.amazonaws.com/test-donations-bucket",
      "fields": {
        "bucket": "test-donations-bucket",
        "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
        "X-Amz-Credential": "ASIA6J6INNI5ZJB4MMGN/20210803/us-east-1/s3/aws4_request",
        "X-Amz-Date": "20210803T152728Z",
        "X-Amz-Security-Token": "test_security_token_Xe9sWTRyZkjVQ2KoXPV7TM8DsVcNtgGOfrSZi4oQANL2kB9MKRPnGHMmYgOToGnBlpWAQIAMimaYg5++nOFIEYL3YPOgrXgHea761dQX1dkN54DIop9C2KkNxgWPNgfHrL2k+mbDdND0AMPqKoYfQ3vcrF6V0pCBCpIgQEUPdk3zvjMwPS4VIUgnlAtxz1Tdn98tktIB+KircD9kCZ19eivxO+vBgEw97vOKKSmlXK7uz8Bwr6tjD85iJS6zK1WkW+bsLo2JJAOS5sbl35mOUrcskOD3aw+VkxfihTQgC3wJNsJTfpz4o0Rn2LL3BQ8CC+CC3YAQbShYFXL3ODfbO8t6xqFPNdokhN2dvnSlUWmtaAJHjgSMgzNVviAqhxi3j8HxNCo6VLXN7HBVJPZO1HWO3e5kk6VPyeie10LnT0YsEVkIig50v2iBXD3gGZ3atzn9OfPc1+OMv8lj1ZJckjHWgA16aOpuvhFt3tj4F5TszpFKVXuOw6Gz6M1sHd9+g9ilATO4IqtFhR8h1cDXxcNGPxvafCSOKqCB2jGsu6sUNZlkpU6Q9S6FUQLkS+L2KTtrdAEpmmMfo17PkLL1YIi9u9mgVyAqFwD8ReoFECM7MD78VHcSp4dR7evryB+IEVAXD2gv6lIS0URJRUaMMLjOsnwG7zA7OsjAAFjM0f6YOmdc415jPEZaDrqqq5rIyxtuvPBBwz5IM2PY5",
        "key": "bulk/f1c1aa80-cd86-422e-acf6-7a5330e26b1e/donations.gz",
        "Policy": "test_policy_tzkVeHKh1hZcFNYN02aEmQi52WVVFMMMJ0lMeVWalpTax2VDSp0dWIzbdV5ll01YnYmaX3jiTOnsch4Mj2lclyO9zIgHSyBTWabk311czh5VpMyhhMRjRXMCaF0K1MQkpMFmRydTcSZh2Rl52mWTVNiZhnjVG1ZEwrUVdXqoRF3uRZ6VUYUkTFWoFNF0UOcLZVoiVVTM0GIzIQoTYbiZIlWOpTEDGw1NoOHVXJZj9ip0lQmGQ2N0kiR3lSqHEp21WWZLt0jTxYlPWcmkookUoQWXxN1WMerDNafYpla2vS4JaTYajNDdcRVuRUwZvMSxXMzXd1Rd1ZlZFRSLRa4N0JcwkyqSQQEUFZZaZwyZ33zzhNHVITTzdUPTemy2nNDM9OhuGzJQwQvzF0nGtLMRtZd1aWCT9TQX9DNZZ0W124CfMC3kbamDUxRxsDFVdecTB0VOnIDk0UUzMlevtZQ4jSJd20lNbMLwRG02VOZCTPZdlSFRV0l2TUMjYNtjQHVyRQmUeY0iH0YlMJj1oQMWlfaDzsVyyT5R5YDHk3ziNneKpIVNFXkjbwz0GeRUxZNlyc0bjCF3tJoBRENT5INW1HZNklq2ttXNkJRYEYF92OJ0Q6FkLbRLDYOFpBXZm0lbNYyniioFmZTNJUoLeBKAYlZWGZMTl1RMMsFUbyFddZsHTjZiwbmrLaOJTjvdVH1Gj1dFlGSdZGYGvMRSdgk2pZN2dVb4VWUteEVENSlUt2NB0IN2TZr1QjMWtlTnpb1MItOKNtRtVB0J4y1l0UEbQ0N31OIB12zzAISzkGkV2C9bpCgFRssvaVlGoi1NytdN0QJWv0ycMl36110kcIGPut9WciWZMNxOldRBTL5nChFW9ktSMRa9jbcTEqsBVddYRJBBxdauFmSRTJn6Jr34LM0DzdVWBOE2S2FUVWNa6ilkRV37d5WlFBxNihxNMFTWNBZMzkTYFVNFNylXtvNX04TEzd4BEdMT2pEhGeBtSmdUemGTNMczkckd02knTcsJ5lTEZWn3c23QdZFZ5AvMwIhVTdAuPZ2XZv5CmVzbYJGGH5tzs0TT0B1ZVRRdK0NHYW0blcbUpBlIGVFBVS1aNeOLKxXmxVVkELt1WzDF2p9uU5xcXDahOsJRhdZDSFVK2UMJEOZllsOMIoJjCn0xmNhzTeTVUJZoMZuCdDddY3NZT1zjh2JYknN1l0DVpGg1X99VP8pbCOtygWxVGHDFxwkamUmU9GcT1bW5cJcvkLUWpw3VWEW3Da9ImaakNaRZUjwjhFc0RWQ0NBEV6S1capbW1W3dcD0Rx6sC1LQWeJ505Cvcx5aUMMiUtSkjrnSGSUhCbyj9xlXpJrk2YKR1G9EaedRL0VyQSF1DVTVIyudQHHAzqs2TrhsLZPbN2MZlJzEW0nkBlEQmcUUnX8IXmLhi1VCjMZGAxGFhtBAbN2NL5YPDzOIhOWUMayn11Yt9RT9mVOoIRdiUwJkWyUNt",
        "X-Amz-Signature": "test_signature_9d2442471b69088b845fb366e6c7ca5fdc26d1aca6b122d8a838c0c51efc9d82"
      }
    }
  }
}

In your response, you will need to make note of the following attributes:

  • id - the unique ID for your bulk donation
  • url - the url for your file upload
  • fields - an object of required fields that will need to be included as form-data as part of your file upload
  • expiresAt - the point in time in which the Bulk Intent's provided url will no longer be valid for upload
    • If your Bulk Intent has expired, you will need to create a new one in order to upload your file.

# Uploading your Bulk File

Once you have your formatted file and Bulk Intent created, you can proceed to uploading your donations to be processed. You will have to make a POST request to the url that was provided to you when creating your Bulk Intent. The following form data fields are required for your upload, which were returned in the fields object - with the exception of your provided file - when your Bulk Intent was created.

The required Bulk File upload fields are:

  • key
  • Policy
  • X-Amz-Algorithm
  • X-Amz-Credential
  • X-Amz-Date
  • X-Amz-Security-Token
  • X-Amz-Signature
  • file - name of your JSON formatted compressed .gz file
    • This must be the last field supplied in your request.

# Sample Request:

# Sample Response:

Upon a successful upload, you will receive a 204 No Content HTTP response from the endpoint.

# Bulk Lifecycle

  1. When a Bulk Intent is created, it will first be in the PENDING state, awaiting a file upload.
  2. Once you have uploaded your file, your Bulk Intent will be in the UPLOADED state.
  3. Within a few minutes, an UPLOADED donation file will begin validation and transition to one of two states:
    1. VALIDATED state if the bulk file was successfully validated
    2. ERROR state if the file failed to validate, due to incorrect formatting or invalid donations. See Validation Errors below.
      1. If your file failed to validate, you will be required to supply a new correctly formatted file
      2. You may use the GET /donations/bulk-intents/{id} endpoint to obtain a link and see the errors with the file
  4. A VALIDATED Bulk Intent will then be picked up to begin PROCESSING
  5. During processing, the Bulk Intent will either finish in one of two states:
    1. PROCESSED state if all of the donations were successfully extracted from your file upload
    2. ERROR state if the one or more donations failed to be extracted from your file upload
  6. PROCESSSED state indicates donations in your bulk-intent are accepted into the system for further donation disbursement.
    1. You may use the GET /donations endpoint to view the accepted donations

# Get the Bulk Intent Details

To obtain your Bulk Intent details and status, you will need to invoke the GET /donations/bulk-intents/{id} endpoint. Let's take a look at what our PROCESSED Bulk Intent would look like.

# Sample Request:

# Sample Response:

{
  "data": {
    "type": "bulkDonationIntent",
    "id": "f1c1aa80-cd86-422e-acf6-7a5330e26b1e",
    "attributes": {
      "status": "PROCESSED",
      "createdAt": "2021-08-03T15:27:28.531Z",
      "updatedAt": "2021-08-03T15:41:56.249Z"
    },
    "links": {
      "related": {
        "href": "https://api.benevity.org/donations?filter[bulk]=f1c1aa80-cd86-422e-acf6-7a5330e26b1e",
        "meta": {
          "uploaded": 3,
          "accepted": 3
        }
      }
    }
  }
}

In the response, we can see when our Bulk Intent was last updated with the updatedAt parameter. In addition, the links attribute contains information relating to the donations that were uploaded as part of your file upload - we can see that there were three donations that were successful extracted from your file, with no errors.

Perhaps the most useful attribute is the href provided that contains the required query to look at each donation individually.

# Validation Errors

If the status of your bulk intent is set to ERROR, there will be additional attributes in the response to help troubleshoot and fix the file for re-upload. The errors attribute will contain details of why the file failed validation, as well a links attribute that shows a presigned URL to download a compressed .gz file. Depending on the type of validation error you receive, the file contents will be different.

  • If there was an issue with validating donation objects, the error file will be donation-errors.gz and contain the invalid donations with error objects pointing to the invalid attributes. Additionally, the links.related.meta attribute will contain counts of total uploaded and invalid donations.
  • If the file itself failed to validate (eg. the file contained invalid JSON), the error file will be donations.gz which is the original submitted file in case you need a copy to fix and re-upload.

The error file URL has a time-to-live of 10 minutes (600 seconds). If you fail to download the file within the 10 minute window, you can call the GET /donations/bulk-intents/{id} endpoint again to obtain a new URL.

# Sample Response (invalid donations):

{
  "data": {
    "type": "bulkDonationIntent",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "status": "ERROR",
      "createdAt": "2021-06-08T18:18:14.630Z",
      "errors": [{
        "code": "INVALID_BULK_DONATIONS",
        "title": "Error validating bulk intent.",
        "detail": "File contains invalid donations for bulk intent ID: 550e8400-e29b-41d4-a716-446655440000",
        "links": {
          "href": "https://s3.us-east-1.amazonaws.com/env-benevity-donation-service-private/bulk/550e8400-e29b-41d4-a716-446655440000/donation-errors.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=...&X-Amz-SignedHeaders=host&x-id=GetObject"
        }
      }],
      "updatedAt": "2021-06-08T18:28:14.630Z"
    },
    "links": {
      "related": {
        "meta": {
          "uploaded": 3,
          "invalid": 1
        }
      }
    }
  }
}

# Sample Donation Error File:

The following is an example of a bulk donation file that had a donation that was missing destination.recipientId.

{
   "data":[
      {
         "type":"donations",
         "attributes":{
            "donor":{
               "receipted":true,
               "fullName":"Benevity User 1",
               "email":"test@benevity.com",
               "address":{
                  "city":"Calgary",
                  "country":"CA",
                  "line1":"5555 Calgary St",
                  "line2":"Suite 101",
                  "state":"AB",
                  "zip":"T0A 1B2"
               }
            },
            "destination":{
               "foundationId":"1XABCDE4UT"
            },
            "funds":{
               "amount":111,
               "currencyCode":"CAD",
               "paymentType":"DONATION_REPORT",
               "source":"COMPANY"
            },
            "errors":[
               {
                  "title":"Bad Request",
                  "status":"400",
                  "detail":"destination requires property \"recipientId\"",
                  "source":{
                     "pointer":"/data/attributes/destination"
                  }
               }
            ]
         }
      }
   ]
}

# Sample Response (invalid JSON):

{
  "data": {
    "type": "bulkDonationIntent",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "status": "ERROR",
      "createdAt": "2021-06-08T18:18:14.630Z",
      "errors": {
        "code": "INVALID_BULK_DONATIONS",
        "title": "Error validating bulk intent.",
        "detail": "Could not parse document string to JSON",
        "links": {
          "href": "https://s3.us-east-1.amazonaws.com/env-benevity-donation-service-private/bulk/550e8400-e29b-41d4-a716-446655440000/donations.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=...&X-Amz-SignedHeaders=host&x-id=GetObject"
        }
      },
      "updatedAt": "2021-06-08T18:28:14.630Z"
    }
  }
}

# Get the Bulk Donation Details

To obtain the details of the individual donations that were contained within your uploaded file, we can use the data.links.related.href from the Get Bulk Intent Details Response, to query for donations that were created with our Bulk Intent ID. By adding the filter filter[bulk]=f1c1aa80-cd86-422e-acf6-7a5330e26b1e to a GET query for donations, we can view the details for each donation, along with their respective statuses.

# Filtering

Required

The filter[bulk]= parameter is required to identify which bulk operation you want to get the donation details for and passing in the Bulk Intent ID from the initial Create a Bulk Intent call.

Optional

The filter[status]= parameter allows you to filter results to only return donations with a specific status. The statuses are based on the Donation Lifecycle documentation.

  • ACCEPTED
  • INITIATED
  • IN_PROGRESS
  • PAID
  • CLEARED
  • DECLINED

The page[size] parameter can be used to request a specific number of results. Note that the range still may be truncated for performance reasons and further pagination would be required.

# Response Details

  • meta
    • count: Contains the total number of results returned
    • page.rangeTruncated: If this attribute is present and true then there is a next page of donations.
  • links: Use the URL listed in each attribute, which includes the page[before] or page[after] parameter and additionally page[size] if supplied, to navigate to the different pages of results for the given filters.
    • previous: The previous set of results
    • next: The next set of available results
  • state.processingStatus: is the current status of the donation based on the description in the Donation Lifecycle documentation

# Sample Request:

# Sample Response:

{
  "meta": {
    "count": 3,
    "page": {
      "rangeTruncated": true
    }
  },
  "links": {
    "next": "https://api.benevity.org/donations?filter[status]=initiated&filter[bulk]=f1c1aa80-cd86-422e-acf6-7a5330e26b1e&page[after]=eyJwayI6IlRZUEUjZG9u...UMDU6MDE6MzcuMDAyWiJ9"
  },
  "data":[
    {
      "type":"donations",
      "id":"c9a03ed1-e87b-4324-ac10-2322b8928db6",
      "attributes":{
        "destination":{
          "foundationId":"1XABCDE4UT",
          "recipientId":"124-119219814RR0001"
        },
        "funds":{
          "amount":111,
          "currencyCode":"CAD",
          "paymentType":"DONATION_REPORT",
          "source":"COMPANY"
        },
        "donor":{
          "fullName":"Benevity User 1",
          "email":"test@benevity.com",
          "receipted":true,
          "address":{
            "line1":"5555 Calgary St",
            "line2":"Suite 101",
            "city":"Calgary",
            "state":"AB",
            "zip":"T0A 1B2",
            "country":"CA"
          },
        },
        "metadata": {
          "vendor-id": "abc-12382",
          "location": "NW Calgary",
          "refill_date": "05/15/2023"
        },
        "state":{
          "processingStatus":"INITIATED",
          "statusLastUpdated":"2021-08-03T15:42:12.001Z",
        },
        "bulkId":"f1c1aa80-cd86-422e-acf6-7a5330e26b1e"
      }
    },
    {
      "type":"donations",
      "id":"6bf6d38c-19c5-4113-b5fa-29826be4efb9",
      "attributes":{
        "destination":{
          "foundationId":"1XABCDE4UT",
          "recipientId":"124-119219814RR0001"
        },
        "funds":{
          "amount":333,
          "currencyCode":"CAD",
          "paymentType":"DONATION_REPORT",
          "source":"COMPANY"
        },
        "metadata": {},
        "payable": {
          "paymentType": "EFT"
        },
        "state":{
          "processingStatus":"PAID",
          "statusLastUpdated":"2021-08-03T15:42:12.124Z",
        },
        "bulkId":"f1c1aa80-cd86-422e-acf6-7a5330e26b1e"
      }
    },
    {
      "type":"donations",
      "id":"e1dd37f6-4f80-4b65-b682-4e045d362572",
      "attributes":{
        "destination":{
          "foundationId":"1XABCDE4UT",
          "recipientId":"124-119219814RR0001"
        },
        "funds":{
          "amount":222,
          "currencyCode":"CAD",
          "paymentType":"DONATION_REPORT",
          "source":"COMPANY"
        },
        "donor":{
          "fullName":"Benevity User 2",
          "email":"test@benevity.com",
          "receipted":true,
          "address":{
            "line1":"5555 Calgary St",
            "line2":"Suite 101",
            "city":"Calgary",
            "state":"AB",
            "zip":"T0A 1B2",
            "country":"CA"
          }
        },
        "metadata": {
          "key1": "value1",
          "key 2": "value 2"
        },
        "payable": {
          "paymentType": "CHEQUE"
        },
        "state":{
          "processingStatus":"CLEARED",
          "statusLastUpdated":"2021-08-03T15:42:12.289Z",
        },
        "bulkId":"f1c1aa80-cd86-422e-acf6-7a5330e26b1e"
      }
    }
  ]
}

# 🚀 ☀️ ⭐️ Congratulations! ⭐️ ☀️ 🚀

Awesome! You have taken another step towards spreading goodness!