Non-Negotiables
- Pass
--rationaleon every command — it is a required field on these agent-tools (a non-empty string, max 1024 chars). With--json, supply it as a"rationale"key in the body. Omitting it returnsHTTP 422 (DEVELOPER_INVALID_SCHEMA), in both agent and human modes. - Scope to the user's own transactions by default (
--transactions_to_retrieve my_transactions) unless they explicitly request broader access. - Only the acting cardholder can complete a transaction revision. Do not attempt revision completion as an admin, manager, or copilot on the cardholder's behalf.
- Show the transaction details before editing. Never blind-edit.
- Never upload a receipt without confirming the match — wrong receipt on wrong transaction is worse than no receipt.
- For bulk edits or receipt sweeps, present the plan and confirm before executing.
- Use
ramp transactions missing {uuid}as the reliable check for whether a receipt is attached — it returnsmissing_receipt: true/falsein real time. Thereceipt_uuidsfield in the list response can be used as a quick filter, but it may be stale (e.g., remaining null even after a successful upload+attach). - Receipt file upload is CLI-only. CLI uploads must be base64-encoded; accepted types are PNG, JPEG, PDF, HEIC, and WEBP.
- MCP users must upload receipts through the Ramp web or mobile app, or forward them from their work email to
receipts@ramp.com. Do not callupload-receipt-filefrom MCP. - The
--user_submitted_fieldsflag tracks provenance — include it to mark which fields the user explicitly provided vs agent-inferred. - All CLI flags use underscores, not hyphens (e.g.,
--from_date,--transaction_uuid).
--rationale is required
Every command in this skill maps to an agent-tool endpoint that requires a
rationale: a non-empty string (max 1024 chars) explaining why you are making
the call. Pass it as --rationale "...", or include a "rationale" key in the
--json body. It is required for both agent (--agent) and human
(agent=false) invocations — omitting it is the #1 cause of HTTP 422 errors on
these tools. The examples below all include it; keep it on every call.
Workflow
Revision-request tasks
When GetAttentionFeed / ramp tasks list returns
TRANSACTION_REVISION_REQUESTED, preserve the task's transaction UUID and
revision request context. Inspect the live transaction, show the requested
changes, and get the cardholder's explicit confirmation before editing.
- Fix every requested agent-editable field with the applicable workflow below. A successful field edit does not itself complete the revision request.
- Re-read the transaction and its missing items. If a requested field still needs user-only work, give the user the returned Ramp link and stop; do not complete the revision prematurely.
- Ask the cardholder for, or have them approve, a nonblank completion reason summarizing how the request was resolved.
- Complete the revision for that same transaction.
MCP:
CompleteTransactionRevision(
transaction_uuid="{transaction_uuid}",
reason="Added the requested receipt and corrected the department",
rationale="Complete the cardholder's resolved transaction revision"
)
CLI:
ramp transactions complete-revision {transaction_uuid} \
--reason "Added the requested receipt and corrected the department" \
--rationale "Complete the cardholder's resolved transaction revision" --agent
Treat the success response's sanction-lift status PENDING_VERIFICATION as an
instruction to verify, not as evidence that a card is unlocked. Poll
GetAttentionFeed / ramp tasks list and ListCards with a finite bound (at
most three rechecks in the current run). On every attention-feed attempt, follow
every section's cursor chain until next_cursor is null and require the number
of unique hydrated task UUIDs to equal each section's total_count; otherwise
the attempt is incomplete and cannot prove the revision task is absent. If a
section's total_count changes between pages, restart that bounded attempt from
the first page rather than combining two snapshots. Success requires a fully
accounted feed in which the same revision task has disappeared
and the exact sanctioned card reports is_spendable: true. If the bound is
exhausted, report the live task, active_locks, and blocking_task_count; do
not say the revision restored card spending.
If revision completion returns:
CompleteTransactionRevisionNotFoundError, re-check the transaction UUID from the task context.CompleteTransactionRevisionPermissionDeniedError, stop and explain that the acting cardholder must complete their own revision.CompleteTransactionRevisionFailedPreconditionError, re-read the attention feed and transaction state. This also covers a replay after the revision is already complete; do not retry it as a new completion event.CompleteTransactionRevisionInternalError, report that completion could not be verified and leave the task outstanding.
Step 1: Find transactions needing attention
ramp transactions list --transactions_to_retrieve my_transactions \
--from_date {start} --state cleared --rationale "Find transactions needing cleanup" --agent --page_size 50
For any transaction, check what's missing:
ramp transactions missing {transaction_uuid} --rationale "Check missing items on the transaction"
Returns missing_receipt (bool), missing_memo (bool), and missing_accounting_items (an array of objects, not category-name strings). Each object has this shape:
{
"category_name": "QuickBooks Online Department",
"category_id": "category-uuid"
}
Present results grouped by what's missing:
Needs attention: 8 transactions ($4,520 total)
Missing receipts (3):
$1,200 United Airlines 2026-03-01
$ 800 Hilton Hotels 2026-03-03
Missing memos (5): ...
Missing accounting categories (2): ...
Step 2: Fill memos
Before writing memos manually, check if Ramp has suggestions:
ramp transactions memo-suggestions {transaction_uuid} --rationale "Fetch AI-suggested memos"
Returns memos[] — an array of suggested memo strings based on the transaction context. Present suggestions and let the user confirm or edit, then:
ramp transactions edit {transaction_uuid} --memo "Q2 team offsite catering" --rationale "Add the user's memo"
To clear a memo, pass an empty string: --memo "" (note: --rationale itself must never be empty).
Step 3: Assign to a fund/spend allocation
ramp transactions edit {transaction_uuid} --fund_uuid {fund_uuid} --rationale "Assign transaction to the chosen fund"
To find available funds:
ramp funds list --funds_to_retrieve MY_FUNDS --include_balance --rationale "List funds to assign the transaction" --agent
Step 4: Set tracking categories (accounting codes)
First, get available categories and their options:
# List categories
ramp accounting categories --rationale "List tracking categories" --agent
# List options for a specific category (use UUID from above)
ramp accounting category-options {tracking_category_uuid} --rationale "List options for the tracking category" --agent --page_size 50
Then edit via --json (tracking categories aren't exposed as named flags).
Important: When using --json, you must include both rationale and transaction_uuid in the body. The --json flag bypasses the CLI's automatic injection of the positional arg and the --rationale flag, so a --json body without a "rationale" key returns HTTP 422.
ramp transactions edit --json '{
"rationale": "Set the tracking category the user chose",
"transaction_uuid": "{transaction_uuid}",
"tracking_category_selections": [
{
"category_uuid": "{category_uuid}",
"option_selection": "{option_uuid}"
}
],
"user_submitted_fields": ["tracking_category_selections"]
}'
Note: the field names inside tracking_category_selections are category_uuid and option_selection — NOT tracking_category_uuid / tracking_category_option_uuid (those are the names returned by the categories list endpoint, not the edit endpoint).
Step 5: Set attendees
ramp transactions edit --json '{
"rationale": "Record attendees for this expense",
"transaction_uuid": "{transaction_uuid}",
"attendee_selections": {
"non_ramp_attendees": [
{"attendee_name": "Jane Smith", "attendee_email": "jane@company.com"}
],
"include_self_as_attendee": false
},
"user_submitted_fields": ["attendee_selections"]
}'
Step 6: Upload receipts
MCP cannot upload receipt files. Direct MCP users to the Ramp web or mobile app, or ask them to forward the receipt from their work email to receipts@ramp.com.
For CLI callers, when the user has a receipt file and wants to attach it to a transaction:
# Base64 encode the file (agent does this)
# For a file at /path/to/receipt.pdf:
base64 -i /path/to/receipt.pdf | tr -d '\n'
# Upload and auto-attach in one step
ramp receipts upload \
--content_type "application/pdf" \
--filename "receipt.pdf" \
--file_content_base64 "{base64_string}" \
--transaction_uuid {txn_uuid} --rationale "Upload the receipt"
The response returns receipt_uuid and attached_to_transaction: true/false.
Omitting --transaction_uuid uploads the receipt without attaching it. The CLI can attach it later with:
ramp receipts attach {receipt_uuid} {transaction_uuid} --rationale "Attach the receipt to the transaction"
Bulk upload from a directory of receipt images/PDFs:
# For each file:
# 1. Determine MIME type from extension (.pdf → application/pdf, .png → image/png, .jpg → image/jpeg)
# 2. Base64 encode: base64 -i <file> | tr -d '\n'
# 3. Match to a transaction by inferring merchant/date from filename or content
# 4. Upload with -n (dry run) first to verify
ramp receipts upload \
--content_type "image/png" \
--filename "uber-2026-03-01.png" \
--file_content_base64 "{base64}" \
--transaction_uuid {txn_uuid} -n --rationale "Upload the receipt"
# If correct, upload for real (without -n)
Step 7: Handle missing receipts without a file
If the user doesn't have a receipt and wants to provide a reason:
ramp transactions explain-missing {transaction_uuid} --reason "Lost receipt — vendor confirmed purchase via email" --rationale "Record why the receipt is missing"
Or generate a link to the missing receipt affidavit form (the user must complete it manually in the browser):
ramp transactions flag-missing {transaction_uuid} --rationale "Generate a missing-receipt affidavit link"
Receipt Matching Heuristics
When matching receipt files to transactions:
- Filename patterns:
merchant-YYYY-MM-DD.pdf,YYYY-MM-DD-merchant.png, etc. - Amount matching: If the receipt shows an amount, match to transactions within ±$1 at that merchant on that date.
- Date matching: Receipt date should be within 1-2 days of
transaction_time. - One receipt per transaction: Before each upload, re-check the live state with
ramp transactions missing {transaction_uuid}and skip whenmissing_receiptisfalse. Do not rely onreceipt_uuidsfrom an earlier list response — it can be stale (see Gotchas) and would trigger a duplicate upload of a recently attached receipt.
Flag uncertain matches as "possible match — verify" rather than auto-uploading.
MIME Type Reference
| Extension | Content type |
|---|---|
.png |
image/png |
.jpg, .jpeg |
image/jpeg |
.pdf |
application/pdf |
.heic |
image/heic |
.webp |
image/webp |
Bulk Cleanup Workflow
For cleaning up many transactions at once:
- Fetch all transactions in the period
- Check
missing_itemson each (or batch-check via individual calls) - Group by what's missing: memo, accounting, receipt
- Present summary: "12 transactions need memos, 5 need accounting categories, 3 need receipts"
- For memos: fetch suggestions for each, present them, let user confirm or edit
- For categories: if most transactions share a category, offer to bulk-apply
- For receipts: match files per the heuristics above, dry-run first, confirm the plan
- Execute sequentially, report progress
Provenance Tracking
The --user_submitted_fields flag tells Ramp which fields the user explicitly provided. This matters for compliance — it distinguishes user intent from agent inference.
Include it when setting fields via --json:
ramp transactions edit --json '{
"rationale": "Add the user's memo",
"transaction_uuid": "{transaction_uuid}",
"memo": "Client dinner with Acme team",
"user_submitted_fields": ["memo"]
}'
Valid values: attendee_selections, attendee_uuids, fund_uuid, memo, tracking_category_selections, trip_selection.
When using named flags (--memo, --fund_uuid), provenance is tracked automatically.
Pagination
If pagination.next_cursor is not null in the JSON envelope, there are more results:
ramp transactions list --transactions_to_retrieve my_transactions \
--from_date {start} --state cleared --agent --page_size 50 \
--next_page_cursor "{cursor}" --rationale "List the user's transactions"
Example Session
User: I have a bunch of transactions that need cleanup
Agent: Let me check what's missing on your recent transactions.
> ramp transactions list --transactions_to_retrieve my_transactions \
> --from_date 2026-03-01 --state cleared --rationale "Find transactions needing cleanup" --agent --page_size 50
Found 8 transactions. Checking missing items on each...
> ramp transactions missing {uuid} --rationale "Check missing items" (×8)
Summary:
5 need memos
2 need accounting categories
1 needs a receipt
Let me get AI-suggested memos for the 5:
> ramp transactions memo-suggestions {uuid} --rationale "Fetch suggested memos" (×5)
Transaction Suggested memo
$135 Facebook Ads 2026-03-02 "Q1 paid social campaign"
$220 AWS 2026-03-05 "March infrastructure costs"
$89 Uber 2026-03-10 (no suggestion)
Want to accept these suggestions, edit them, or write your own?
User: Accept Facebook and AWS. The Uber was a client dinner ride.
Agent: Updating 3 transactions:
> ramp transactions edit {fb-uuid} --memo "Q1 paid social campaign" --rationale "Apply accepted memo suggestion"
> ramp transactions edit {aws-uuid} --memo "March infrastructure costs" --rationale "Apply accepted memo suggestion"
> ramp transactions edit {uber-uuid} --memo "Client dinner transportation" --rationale "Set memo from user input"
Done. Now the receipt: United Airlines, $1,200 on 2026-03-05.
User: It's at ~/Downloads/united-mar5.pdf
Agent: > base64 -i ~/Downloads/united-mar5.pdf | tr -d '\n'
> ramp receipts upload --content_type "application/pdf" \
> --filename "united-mar5.pdf" \
> --file_content_base64 "{base64}" \
> --transaction_uuid "abc-123" -n --rationale "Upload the receipt"
Dry run looks correct — uploading to United Airlines ($1,200) on 2026-03-05.
Proceed?
User: yes
Agent: > ramp receipts upload --content_type "application/pdf" ...
Receipt uploaded and attached (receipt_uuid: def-456).
2 transactions still need accounting categories — want to tackle those next?
When NOT to Use
- Approving or rejecting items — use ramp-approval-dashboard
- Vendor documents (W-9s, contracts, COIs) — use ramp-manage-vendors
- Company-wide spend reporting — the CLI is scoped to your own data; use ramp-spend-analysis or the Ramp dashboard
Gotchas
| Issue | Fix |
|---|---|
HTTP 422 "API error 422: There was an error." |
You omitted rationale. It's a required field on these agent-tools (DEVELOPER_INVALID_SCHEMA) — add --rationale "...", or a "rationale" key in the --json body. Required for both agent and human (agent=false) calls. Not a permissions problem. |
--dry_run succeeds but the real call 422s |
--dry_run only prints the body; it does not validate it. Confirm rationale is present before sending. |
amount is a formatted string ("$135.40") |
Strip "$" and "," for numeric operations |
--state values are lowercase |
Use cleared, pending, declined — not uppercase |
Tracking categories require --json |
Named flags only cover --memo and --fund_uuid. When using --json, include both rationale and transaction_uuid in the body. |
| Category field names differ between endpoints | accounting category-options returns tracking_category_option_uuid, but transactions edit expects category_uuid + option_selection |
memo-suggestions may return empty |
Not all transactions have enough context for suggestions |
accounting category-options paginates with integers |
Unlike other endpoints, the cursor is a number, not a string |
--transactions_to_retrieve is required |
Always include it on transactions list. Use my_transactions for personal, all_transactions_across_entire_business for admin scope |
| Searching for specific transactions | Use --reason_memo_merchant_or_user_name_text_search "query" (min 3 chars) |
| Large receipt files may hit shell arg limits | CLI: for files >100KB, write base64 to a temp file and use --json with the content read from file. |
| Receipt uploads from MCP | Receipt file upload is unavailable. Direct users to the Ramp web/mobile app or receipts@ramp.com. |
| Duplicate upload risk | Re-check ramp transactions missing {uuid} immediately before uploading; skip when missing_receipt is false. receipt_uuids alone can be stale. |
| Comment on a transaction | ramp general comment {uuid} --ramp_object_type transaction --message "text" --rationale "Add a comment for the user" |