Annotate a Transaction (memo, category & attachment)
You can enrich any transaction with a memo, a category, and/or an attachment (e.g. receipts, invoices, purchase orders). Annotations can be added at the time of the original transaction or updated afterward using the updateTransactionMetadata mutation.
Annotations are supported on:
- Deposits (
depositCashBalance1) - Gift card purchases (
purchaseGiftCard) - Wallet transfers (
createTransfer,transferInternalBalance) - Virtual card creation (
createVirtualCard)attachmentis excluded
How it works
- Optional: If you want to attach a file, uplaod it first via the REST upload endpoint. You'll get back an
attachmentId. - Pass
memo,transactionCategory, and/orattachmentIdinto your mutation input — either at transaction time or later viaupdateTransactionMetadata. - Read annotations back on
getTransactions,getUserPurchases, or the mutation response. TheattachmentUrlfield returns a short-lived signed URL for file access.
Step 1: Upload an attachment (optional)
This is a REST endpoint, not a GraphQL mutation
Endpoint
POST /api/v1/file-upload/transaction-memo-attachment
Authentication
Authorization: Bearer <YOUR_USER_ACCESS_TOKEN>
Request
Send the file as multipart/form-data with the field name file.
Accepted types: application/pdf, image/png
JPEG is not accepted for transaction attachments.
Sample Request
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/file-upload/transaction-memo-attachment \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
-F "[email protected]"Response
{
"attachmentId": "3f2a1b4c-e5d6-7890-abcd-ef1234567890"
}Copy the attachmentId — you'll pass it into your mutation input in the next step.
The
attachmentIdis scoped to your account. The system verifies the file exists in your account's storage when you submit the mutation. An ID from a different account will be rejected.
Upload Errors
| Cause | Status | Details |
|---|---|---|
| No file included in request | 400 | Missing file |
| File type not allowed (e.g. JPEG) | 400 | INVALID_ARGUMENTS |
Step 2: Annotate the transaction
You can provide annotations at the time of the original transaction or update them afterward.
Option A — At transaction time
The following mutations accept memo, transactionCategory, and attachmentId as optional fields in their input:
depositCashBalance→DepositCashBalanceInputpurchaseGiftCard→PurchaseGiftCardInputcreateTransfer→CreateTransferInputtransferInternalBalance→TransferInternalBalanceInput
Annotation Fields
| Field | Type | Description |
|---|---|---|
memo | String | Free-text note. Max 255 characters. |
transactionCategory | String | Category label. Free-form — categories are created automatically on first use and reused if the same name is passed again. |
attachmentId | String | The ID returned by the upload endpoint. The file must be uploaded before submitting the mutation. |
Sample — Purchase Gift Card with Annotation
mutation purchaseGiftCard($input: PurchaseGiftCardInput!) {
purchaseGiftCard(input: $input) {
purchaseDisplayId
purchaseAmount
memo
transactionCategory
attachmentUrl
giftCard {
giftCardId
status
}
}
}{
"idempotencyKey": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
"offerId": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
"amount": 50.00,
"balanceAmount": 50.00,
"memo": "Team lunch — Q2",
"transactionCategory": "Meals & Entertainment",
"attachmentId": "3f2a1b4c-e5d6-7890-abcd-ef1234567890"
}Option B — After the transaction (updateTransactionMetadata)
updateTransactionMetadata)Use this mutation to add or update annotations on any existing transaction.
Partial update semantics: Only the fields you include are updated. Omitted fields are left unchanged. Pass
nullto clear a field.
Mutation
mutation updateTransactionMetadata($input: UpdateTransactionMetadataInput!) {
updateTransactionMetadata(input: $input) {
record_id
memo
transactionCategory
attachmentUrl
}
}UpdateTransactionMetadataInput
| Field | Type | Required | Description |
|---|---|---|---|
recordId | UUID! | Yes | The record_id of the transaction to update. |
memo | String | No | Free-text note. Max 255 characters. Omit to leave unchanged; pass null to clear. |
transactionCategory | String | No | Category label. Omit to leave unchanged; pass null to clear. |
attachmentId | String | No | ID from the upload endpoint. Omit to leave unchanged; pass null to clear. |
Required Scopes
LIST_PAYMENT and LIST_PURCHASES
Sample — Add a memo and category
{
"recordId": "550e8400-e29b-41d4-a716-446655440000",
"memo": "Q1 vendor payment",
"transactionCategory": "Operating Expenses"
}Sample — Attach a file to an existing transaction
{
"recordId": "550e8400-e29b-41d4-a716-446655440000",
"attachmentId": "3f2a1b4c-e5d6-7890-abcd-ef1234567890"
}Sample — Clear a memo
{
"recordId": "550e8400-e29b-41d4-a716-446655440000",
"memo": null
}Sample Response
{
"data": {
"updateTransactionMetadata": {
"record_id": "550e8400-e29b-41d4-a716-446655440000",
"memo": "Q1 vendor payment",
"transactionCategory": "Operating Expenses",
"attachmentUrl": "https://storage.googleapis.com/..."
}
}
}Errors
| Cause | Error |
|---|---|
recordId not found or belongs to a different account | INVALID_ARGUMENTS — transaction not found |
| Transaction type does not support metadata | INVALID_ARGUMENTS — transaction does not support metadata |
attachmentId is not a valid UUID | INVALID_ARGUMENTS — Invalid attachment ID |
| File not found in storage (not uploaded, or wrong account) | INVALID_ARGUMENTS — Attachment file not found. Please upload the file first. |
Reading annotations
Annotations are returned on the following:
| Query / Mutation | Type | Fields |
|---|---|---|
getTransactions | Transaction | memo, transactionCategory, attachmentUrl |
getUserPurchases | UserPurchase | memo, transactionCategory, attachmentUrl |
updateTransactionMetadata | Transaction | memo, transactionCategory, attachmentUrl |
depositCashBalance | CashBalanceDeposit | attachmentUrl |
attachmentUrlis a signed URL. It expires shortly after being generated. Do not store it — re-fetch the transaction when you need to display or access the file.
Updated 5 days ago
