# 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 donationurl
- the url for your file uploadfields
- an object of required fields that will need to be included asform-data
as part of your file uploadexpiresAt
- 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
- When a Bulk Intent is created, it will first be in the
PENDING
state, awaiting a file upload. - Once you have uploaded your file, your Bulk Intent will be in the
UPLOADED
state. - Within a few minutes, an
UPLOADED
donation file will begin validation and transition to one of two states:VALIDATED
state if the bulk file was successfully validatedERROR
state if the file failed to validate, due to incorrect formatting or invalid donations. See Validation Errors below.- If your file failed to validate, you will be required to supply a new correctly formatted file
- You may use the GET /donations/bulk-intents/{id} endpoint to obtain a link and see the errors with the file
- A
VALIDATED
Bulk Intent will then be picked up to beginPROCESSING
- During processing, the Bulk Intent will either finish in one of two states:
PROCESSED
state if all of the donations were successfully extracted from your file uploadERROR
state if the one or more donations failed to be extracted from your file upload
PROCESSSED
state indicates donations in your bulk-intent are accepted into the system for further donation disbursement.- 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, thelinks.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 returnedpage.rangeTruncated
: If this attribute is present andtrue
then there is anext
page of donations.
links
: Use the URL listed in each attribute, which includes thepage[before]
orpage[after]
parameter and additionallypage[size]
if supplied, to navigate to the different pages of results for the given filters.previous
: The previous set of resultsnext
: 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!