Playbook — Quarterly Finance Reporting (for CFOs)
This playbook walks a CFO or finance lead through the end-of-quarter reporting cycle in Alloy. It covers verifying project setup, ensuring time entries are approved, setting labor rates, generating capitalization reports, exporting CSV for ERP import, and reviewing budget utilization — all through the API. The guide assumes you already have an Alloy account, an organization, and projects with time tracking enabled.
For the full time tracking API, see Time Tracking & Finance. For finance-specific setup, see For Finance Teams.
1. Prerequisites and Setup
Set shell variables so the examples are copy-pasteable:
BASE_URL="http://localhost:3000"
TOKEN="<your-access-token>"
ORG_ID="<your-org-uuid>"
Confirm you can reach the server:
curl -s "$BASE_URL/health" | jq .
{
"status": "ok",
"service": "alloy",
"version": "0.1.0",
"database": "...",
"db_healthy": true,
"migration_version": "...",
"uptime_seconds": "..."
}
Check your identity and role:
curl -s "$BASE_URL/api/v1/auth/me" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"user_id": "...",
"org_id": "...",
"email": "...",
"role": "..."
}
You need Admin or Owner role to approve time entries and manage labor rates. Viewer role is sufficient for read-only report access.
CLI shortcut:
alloy auth me
2. Audit Project Finance Fields
Before generating reports, verify every project has the correct finance metadata. List all projects in the organization:
curl -s "$BASE_URL/api/v1/projects?org_id=$ORG_ID&limit=50" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"org_id": "...",
"key": "...",
"name": "...",
"description": "...",
"ticket_counter": "...",
"capitalization_type": "...",
"development_phase": "...",
"cost_center_id": "...",
"budget_cents": "...",
"budget_period": "..."
}
],
"next_cursor": null,
"has_more": false
}
For each project, confirm these fields are set:
| Field | What to check |
|---|---|
capitalization_type | Capex or Opex — determines accounting treatment |
development_phase | Preliminary, AppDevelopment, or PostImplementation |
cost_center_id | Matches your GL chart of accounts |
budget_cents | Correct for the quarter |
budget_period | Quarterly for quarterly reporting |
Fix any missing fields before proceeding:
curl -s -X PATCH "$BASE_URL/api/v1/projects/$PROJECT_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"capitalization_type": "Capex",
"development_phase": "AppDevelopment",
"cost_center_id": "ENG-002",
"budget_cents": 10000000,
"budget_period": "Quarterly"
}' | jq .
{
"id": "...",
"org_id": "...",
"key": "...",
"name": "...",
"description": "...",
"ticket_counter": "...",
"capitalization_type": "Capex",
"development_phase": "AppDevelopment",
"cost_center_id": "ENG-002",
"budget_cents": 10000000,
"budget_period": "Quarterly"
}
CLI shortcut:
alloy project listandalloy project update
3. Verify Labor Rates
Capitalization reports multiply hours by loaded labor rates. Verify that every engineer who logged time has a current rate. Check rates for a specific user:
curl -s "$BASE_URL/api/v1/users/$USER_ID/orgs/$ORG_ID/labor-rates" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"user_id": "...",
"org_id": "...",
"loaded_rate_cents": "...",
"effective_date": "...",
"created_at": "...",
"updated_at": "..."
}
],
"next_cursor": null,
"has_more": false
}
If a user is missing a rate, or the rate needs updating for the new quarter, set one:
curl -s -X POST "$BASE_URL/api/v1/labor-rates" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"user_id\": \"$USER_ID\",
\"org_id\": \"$ORG_ID\",
\"loaded_rate_cents\": 17500,
\"effective_date\": \"2026-04-01\"
}" | jq .
{
"id": "...",
"user_id": "...",
"org_id": "...",
"loaded_rate_cents": 17500,
"effective_date": "2026-04-01",
"created_at": "...",
"updated_at": "..."
}
A loaded_rate_cents of 17500 means $175.00/hour. The system uses the
most recent rate on or before the time entry date, so historical reports
remain accurate when rates change.
4. Review and Approve Pending Time Entries
Only Approved time entries appear in capitalization reports. Check for any submitted entries still awaiting approval:
curl -s "$BASE_URL/api/v1/time-entries/submitted" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [],
"next_cursor": null,
"has_more": false
}
When there are pending entries, each item includes id, user_id,
ticket_id, project_id, date, duration_minutes, description,
activity_type, and status (Submitted).
Approve each entry:
curl -s -X POST "$BASE_URL/api/v1/time-entries/$TIME_ENTRY_ID/approve" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"user_id": "...",
"ticket_id": "...",
"project_id": "...",
"date": "...",
"duration_minutes": "...",
"description": "...",
"activity_type": "...",
"status": "Approved",
"approved_by": "...",
"approved_at": "...",
"created_at": "...",
"updated_at": "..."
}
Ensure all time entries for the quarter are in Approved status before generating reports. Unapproved entries will not be included.
Tip: Send a reminder to engineering leads a week before quarter-end to submit all outstanding time entries.
5. Generate the Capitalization Report
Run the capitalization report for the quarter. Use the first month of the
quarter as the period (the report aggregates the full quarter when
budget_period is Quarterly):
curl -s "$BASE_URL/api/v1/reports/capitalization?period=2026-01" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"period": "2026-01",
"projects": []
}
When projects have approved time entries with labor rates configured, each project entry includes:
| Field | Description |
|---|---|
project_id | Project UUID |
project_key | Short project key (e.g. PAY) |
project_name | Human-readable name |
capitalization_type | Capex or Opex |
development_phase | ASC 350-40 phase |
cost_center_id | GL mapping code |
total_hours | Sum of approved hours |
total_amount_cents | Hours multiplied by labor rates |
breakdown | Per-activity-type detail |
6. Generate Budget Utilization Report
Add include_budget=true to see budget vs. actual spend:
curl -s "$BASE_URL/api/v1/reports/capitalization?period=2026-01&include_budget=true" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"period": "2026-01",
"projects": []
}
When there are approved entries, each project also includes:
| Field | Description |
|---|---|
budget_cents | Total budget for the period |
spent_cents | Approved time cost for the period |
budget_remaining_cents | budget_cents - spent_cents |
budget_utilization_pct | Percentage of budget consumed |
Flag any projects over 90% utilization for CFO review.
7. Group by Cost Center
For department-level reporting, filter by cost center:
curl -s "$BASE_URL/api/v1/reports/capitalization?period=2026-01&cost_center_id=ENG-002" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"period": "2026-01",
"projects": []
}
This narrows the report to only projects assigned to cost center
ENG-002. Run this for each cost center to produce department-level
summaries for the CFO deck.
8. Group by Team
For team-level reporting, use the group_by=team parameter:
curl -s "$BASE_URL/api/v1/reports/capitalization?period=2026-01&group_by=team&include_budget=true" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"period": "2026-01",
"teams": []
}
When teams have approved time, each entry includes team_id,
team_name, total_hours, total_amount_cents, and a projects
breakdown with per-project budget utilization.
9. Export CSV for ERP Import
Export the full capitalization report as CSV for import into SAP, Oracle, NetSuite, or your spreadsheet workflow:
curl -s "$BASE_URL/api/v1/reports/capitalization/export?period=2026-01" \
-H "Authorization: Bearer $TOKEN" -o capitalization-Q1-2026.csv
The CSV includes these columns:
Period,Project,ProjectKey,Employee,Department,CostCenter,Hours,ActivityType,Phase,CapExOpEx,LoadedRate,Amount,Team,Tags,BudgetCents,SpentCents,Utilization
Export filtered by cost center for department-level files:
curl -s "$BASE_URL/api/v1/reports/capitalization/export?period=2026-01&cost_center_id=ENG-002" \
-H "Authorization: Bearer $TOKEN" -o eng-002-Q1-2026.csv
Export grouped by team:
curl -s "$BASE_URL/api/v1/reports/capitalization/export?period=2026-01&group_by=team" \
-H "Authorization: Bearer $TOKEN" -o team-report-Q1-2026.csv
Automation tip: Schedule CSV exports as a cron job at the start of each month. The API is stateless — the same curl command produces a fresh report each time.
10. Review Activity Type Classification
During audit prep, verify that activity types are correctly classified. The classification determines CapEx vs. OpEx treatment:
| Activity Type | CapEx Eligible | Notes |
|---|---|---|
Coding | Yes | Core development work |
Testing | Yes | Writing and running tests |
CodeReview | Yes | Pull request reviews |
Design | Yes | UI/UX design work |
Architecture | Yes | System design decisions |
Documentation | Yes | Technical documentation |
Deployment | Yes | CI/CD and release work |
BugFixing | Yes (Development) | Only during AppDevelopment phase |
PM | Depends | Capitalizable during AppDevelopment |
Requirements | Planning only | Capitalizable during Preliminary phase |
Meetings | Depends | Context-dependent |
Training | No | Always OpEx |
Maintenance | No | Always OpEx |
Filter the report by activity type to spot-check classification:
curl -s "$BASE_URL/api/v1/reports/capitalization?period=2026-01&activity_type=Maintenance" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"period": "2026-01",
"projects": []
}
All Maintenance hours should appear as OpEx regardless of project
phase. If capitalizable hours appear under Maintenance, flag the
entries for reclassification.
11. Quarterly Close Checklist
Run through this checklist at the end of each quarter:
- Audit project fields — Verify
capitalization_type,development_phase,cost_center_id, andbudget_centson every project (Section 2) - Verify labor rates — Confirm all engineers have current loaded rates with correct effective dates (Section 3)
- Approve all time — Clear the submitted queue; reject or return any entries that need correction (Section 4)
- Generate capitalization report — Run for the quarter period with
include_budget=true(Sections 5-6) - Review by cost center — Generate per-department reports for GL mapping (Section 7)
- Review by team — Generate team-level reports for management review (Section 8)
- Export CSV — Export full and filtered CSVs for ERP import (Section 9)
- Spot-check activity types — Filter by
MaintenanceandTrainingto verify OpEx classification (Section 10) - Archive exports — Store CSV files in your document management system with the quarter label
- Update budgets — Set
budget_centsfor the next quarter on all active projects - Adjust rates — Add new labor rates with future effective dates for any pending promotions or annual adjustments
- Sign off — Record quarter-close completion in your audit trail
12. Automating the Quarterly Cycle
Script the entire quarterly cycle for hands-off execution. Here is the reporting portion as a shell script:
QUARTER="2026-01"
OUTPUT_DIR="./reports/Q1-2026"
mkdir -p "$OUTPUT_DIR"
Export the main capitalization report:
curl -s "$BASE_URL/api/v1/reports/capitalization/export?period=2026-01" \
-H "Authorization: Bearer $TOKEN" -o "$OUTPUT_DIR/capitalization.csv"
Export by cost center (repeat for each department):
curl -s "$BASE_URL/api/v1/reports/capitalization/export?period=2026-01&cost_center_id=ENG-001" \
-H "Authorization: Bearer $TOKEN" -o "$OUTPUT_DIR/eng-001.csv"
Export by team:
curl -s "$BASE_URL/api/v1/reports/capitalization/export?period=2026-01&group_by=team" \
-H "Authorization: Bearer $TOKEN" -o "$OUTPUT_DIR/by-team.csv"
MCP shortcut: Use the
get_capitalization_reportandget_time_reportMCP tools to pull reports programmatically from any MCP-compatible client.
Further reading:
- Time Tracking & Finance — full time entry lifecycle, labor rates, and reporting API
- For Finance Teams — finance team setup and day-to-day operations
- Teams, Roles & Permissions — access control and role requirements
- API Reference — complete endpoint documentation
- MCP Tools Reference — MCP automation for reports