curl --request POST \
--url https://api.grainledger.com/api/v1/batches \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"externalReference": "Sunday online gifts",
"batchDate": "2026-08-16"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({externalReference: 'Sunday online gifts', batchDate: '2026-08-16'})
};
fetch('https://api.grainledger.com/api/v1/batches', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.grainledger.com/api/v1/batches"
payload = {
"externalReference": "Sunday online gifts",
"batchDate": "2026-08-16"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "<string>",
"externalBatchId": "<string>",
"externalReference": "<string>",
"batchDate": "2023-11-07T05:31:56Z",
"totals": {
"gross": 123,
"fees": 123,
"net": 123,
"paymentCount": 123,
"donationCount": 123
},
"status": "OPEN",
"isCommitted": true,
"committedAt": "2023-11-07T05:31:56Z",
"processedAt": "2023-11-07T05:31:56Z",
"errorMessage": "<string>",
"givingIntegration": {
"id": "<string>",
"provider": "<string>",
"name": "<string>"
},
"merchant": {
"id": "<string>",
"name": "<string>",
"campusId": "<string>",
"dimensionValueId": "<string>"
},
"settlement": {
"id": "<string>",
"provider": "<string>",
"externalReference": "<string>",
"status": "<string>",
"totalNet": 123
},
"journalEntry": {
"id": "<string>",
"entryNumber": "<string>",
"referenceNumber": "<string>"
},
"dimensions": [
{
"dimensionId": "<string>",
"dimensionValueId": "<string>",
"dimensionName": "<string>",
"dimensionValueName": "<string>"
}
],
"fundSplits": [
{
"fundId": "<string>",
"fundName": "<string>",
"amount": 123
}
],
"contributionIds": [
"<string>"
],
"isFrozen": true,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}Create giving batch
Creates an empty or populated batch without posting accounting. contributionIds atomically replace membership.
curl --request POST \
--url https://api.grainledger.com/api/v1/batches \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"externalReference": "Sunday online gifts",
"batchDate": "2026-08-16"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({externalReference: 'Sunday online gifts', batchDate: '2026-08-16'})
};
fetch('https://api.grainledger.com/api/v1/batches', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.grainledger.com/api/v1/batches"
payload = {
"externalReference": "Sunday online gifts",
"batchDate": "2026-08-16"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "<string>",
"externalBatchId": "<string>",
"externalReference": "<string>",
"batchDate": "2023-11-07T05:31:56Z",
"totals": {
"gross": 123,
"fees": 123,
"net": 123,
"paymentCount": 123,
"donationCount": 123
},
"status": "OPEN",
"isCommitted": true,
"committedAt": "2023-11-07T05:31:56Z",
"processedAt": "2023-11-07T05:31:56Z",
"errorMessage": "<string>",
"givingIntegration": {
"id": "<string>",
"provider": "<string>",
"name": "<string>"
},
"merchant": {
"id": "<string>",
"name": "<string>",
"campusId": "<string>",
"dimensionValueId": "<string>"
},
"settlement": {
"id": "<string>",
"provider": "<string>",
"externalReference": "<string>",
"status": "<string>",
"totalNet": 123
},
"journalEntry": {
"id": "<string>",
"entryNumber": "<string>",
"referenceNumber": "<string>"
},
"dimensions": [
{
"dimensionId": "<string>",
"dimensionValueId": "<string>",
"dimensionName": "<string>",
"dimensionValueName": "<string>"
}
],
"fundSplits": [
{
"fundId": "<string>",
"fundName": "<string>",
"amount": 123
}
],
"contributionIds": [
"<string>"
],
"isFrozen": true,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization."
}Authorizations
Organization API key created in Grain Settings → API. The key determines the organization and is limited to its assigned resource scopes. Write scopes imply the corresponding read scope.
Headers
Required with OAuth access tokens for resource requests. Omit only for GET /api/v1/organizations. Optional with organization API keys; if supplied with an API key, it must match the key's organization.
Body
1Generated when omitted.
When omitted, Grain's non-syncing manual giving integration is used.
10000OPEN, COMMITTED, FAILED Response
Created giving batch
Giving batch whose totals and donation count are derived from current contribution membership. Metadata and sync diagnostics are excluded.
Calendar day represented as a UTC-midnight ISO timestamp.
OPEN, COMMITTED, SETTLED, FAILED