curl --request POST \
--url https://api.grainledger.com/api/v1/transactions/{id}/approve \
--header 'Authorization: Bearer <token>'const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.grainledger.com/api/v1/transactions/{id}/approve', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.grainledger.com/api/v1/transactions/{id}/approve"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text){
"id": "<string>",
"externalId": "<string>",
"description": "<string>",
"amount": 1,
"direction": "INFLOW",
"transactionType": "DEPOSIT",
"date": "2023-11-07T05:31:56Z",
"referenceNumber": "<string>",
"source": "MANUAL",
"reviewStatus": "DRAFT",
"isReconciled": true,
"is1099Excluded": true,
"bankAccount": {
"id": "<string>",
"name": "<string>",
"mask": "<string>",
"accountType": "<string>"
},
"sourceAccount": {
"id": "<string>",
"accountNumber": "<string>",
"name": "<string>",
"accountType": "<string>"
},
"fund": {
"id": "<string>",
"name": "<string>",
"fundType": "<string>"
},
"vendor": {
"id": "<string>",
"name": "<string>"
},
"dimensions": [
{
"dimensionId": "<string>",
"dimensionValueId": "<string>",
"dimensionName": "<string>",
"dimensionValueName": "<string>"
}
],
"coding": {
"status": "UNCATEGORIZED",
"journalEntryId": "<string>",
"entryNumber": "<string>",
"isSplit": true,
"lines": [
{
"id": "<string>",
"account": {
"id": "<string>",
"accountNumber": "<string>",
"name": "<string>",
"accountType": "<string>"
},
"fund": {
"id": "<string>",
"name": "<string>",
"fundType": "<string>"
},
"amount": 123,
"memo": "<string>",
"dimensions": [
{
"dimensionId": "<string>",
"dimensionValueId": "<string>",
"dimensionName": "<string>",
"dimensionValueName": "<string>"
}
]
}
],
"missingRequiredDimensions": [
{
"dimensionId": "<string>",
"dimensionName": "<string>"
}
]
},
"suggestion": {
"account": {
"id": "<string>",
"accountNumber": "<string>",
"name": "<string>",
"accountType": "<string>"
},
"fund": {
"id": "<string>",
"name": "<string>",
"fundType": "<string>"
},
"confidence": 50
},
"attachmentCount": 1,
"canManage": 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.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}Approve a transaction
Posts the transaction’s journal entry to the ledger. Requires the transactions:approve scope. Safe to retry; approving an approved transaction returns it unchanged. Fails when required dimensions are missing or the period is locked.
curl --request POST \
--url https://api.grainledger.com/api/v1/transactions/{id}/approve \
--header 'Authorization: Bearer <token>'const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.grainledger.com/api/v1/transactions/{id}/approve', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.grainledger.com/api/v1/transactions/{id}/approve"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text){
"id": "<string>",
"externalId": "<string>",
"description": "<string>",
"amount": 1,
"direction": "INFLOW",
"transactionType": "DEPOSIT",
"date": "2023-11-07T05:31:56Z",
"referenceNumber": "<string>",
"source": "MANUAL",
"reviewStatus": "DRAFT",
"isReconciled": true,
"is1099Excluded": true,
"bankAccount": {
"id": "<string>",
"name": "<string>",
"mask": "<string>",
"accountType": "<string>"
},
"sourceAccount": {
"id": "<string>",
"accountNumber": "<string>",
"name": "<string>",
"accountType": "<string>"
},
"fund": {
"id": "<string>",
"name": "<string>",
"fundType": "<string>"
},
"vendor": {
"id": "<string>",
"name": "<string>"
},
"dimensions": [
{
"dimensionId": "<string>",
"dimensionValueId": "<string>",
"dimensionName": "<string>",
"dimensionValueName": "<string>"
}
],
"coding": {
"status": "UNCATEGORIZED",
"journalEntryId": "<string>",
"entryNumber": "<string>",
"isSplit": true,
"lines": [
{
"id": "<string>",
"account": {
"id": "<string>",
"accountNumber": "<string>",
"name": "<string>",
"accountType": "<string>"
},
"fund": {
"id": "<string>",
"name": "<string>",
"fundType": "<string>"
},
"amount": 123,
"memo": "<string>",
"dimensions": [
{
"dimensionId": "<string>",
"dimensionValueId": "<string>",
"dimensionName": "<string>",
"dimensionValueName": "<string>"
}
]
}
],
"missingRequiredDimensions": [
{
"dimensionId": "<string>",
"dimensionName": "<string>"
}
]
},
"suggestion": {
"account": {
"id": "<string>",
"accountNumber": "<string>",
"name": "<string>",
"accountType": "<string>"
},
"fund": {
"id": "<string>",
"name": "<string>",
"fundType": "<string>"
},
"confidence": 50
},
"attachmentCount": 1,
"canManage": 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.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}{
"code": "forbidden",
"message": "You do not have access to this organization.",
"error": "You do not have access to this organization.",
"details": {
"fields": [
{
"field": "amount",
"code": "invalid_type"
}
]
}
}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.
Path Parameters
Resource ID
Response
Approved transaction
Integrator-supplied ID, unique within the organization.
Always positive. Use direction for the sign.
x >= 0INFLOW, OUTFLOW DEPOSIT, WITHDRAWAL, TRANSFER, ADJUSTMENT Calendar day represented as a UTC-midnight ISO timestamp.
MANUAL, PLAID, IMPORT, PLANNING_CENTER, PUSHPAY, TITHELY, SUBSPLASH, ROCK_RMS, RAMP, DIVVY, OVERFLOW DRAFT, PENDING_REVIEW, PENDING_TRANSFER_MATCH, PENDING_TRANSFER_CONFIRM, AUTO_CATEGORIZED, APPROVED, POSTED, REJECTED Hide child attributes
Hide child attributes
UNCATEGORIZED has no journal entry. CATEGORIZED has a draft entry. APPROVED has a posted entry.
UNCATEGORIZED, CATEGORIZED, APPROVED Category-side journal lines. The bank or card line is omitted.
Hide child attributes
Hide child attributes
Journal entry line ID.
Allocated amount. Positive values allocate the transaction; negative values offset another line.
Rule or AI coding suggestion awaiting review.
Hide child attributes
Hide child attributes
0 <= x <= 100x >= 0Whether this credential can edit the transaction.