Get an attachment download URL
curl --request GET \
--url https://api.grainledger.com/api/v1/transactions/{id}/attachments/{fileId}/download \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.grainledger.com/api/v1/transactions/{id}/attachments/{fileId}/download', 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}/attachments/{fileId}/download"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"url": "<string>",
"expiresAt": "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"
}
]
}
}Transactions
Get an attachment download URL
Returns a signed URL that expires after 15 minutes.
GET
https://api.grainledger.com
/
api
/
v1
/
transactions
/
{id}
/
attachments
/
{fileId}
/
download
Get an attachment download URL
curl --request GET \
--url https://api.grainledger.com/api/v1/transactions/{id}/attachments/{fileId}/download \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.grainledger.com/api/v1/transactions/{id}/attachments/{fileId}/download', 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}/attachments/{fileId}/download"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"url": "<string>",
"expiresAt": "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
ApiKeyAuthGrainOAuth2BearerAuth
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.
Last modified on October 10, 2026