{"openapi":"3.1.0","info":{"title":"GET /api/v1/people/{person_id}/ledger","version":"1.0.0","description":"One person's ledger"},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/people/{person_id}/ledger":{"get":{"tags":["people"],"summary":"One person's ledger","description":"Journal lines about the person: linked to them on the roster, or unlinked and named like them. Folded into months by pay component (pay, bonus, burden, reimbursement) with what is owed to them (payable) and advanced to them (advance), all time. Owners and admins only.","operationId":"person_ledger","parameters":[{"name":"person_id","in":"path","required":true,"schema":{"type":"string","title":"Person Id"}},{"name":"months","in":"query","required":false,"schema":{"type":"integer","maximum":36,"minimum":1,"description":"Trailing calendar months.","default":12,"title":"Months"},"description":"Trailing calendar months."},{"name":"lines_limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Most lines returned.","default":200,"title":"Lines Limit"},"description":"Most lines returned."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_PersonLedgerResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"person_ledger_api_v1_people__person_id__ledger_get"}}},"components":{"schemas":{"PersonLedgerLine":{"properties":{"line_id":{"type":"string","title":"Line Id"},"journal_entry_id":{"type":"string","title":"Journal Entry Id"},"entry_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entry Number"},"date":{"type":"string","format":"date","title":"Date"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"ledger_id":{"type":"string","title":"Ledger Id"},"ledger_name":{"type":"string","title":"Ledger Name"},"component":{"type":"string","enum":["pay","bonus","burden","reimbursement","payable","advance","other"],"title":"Component"},"debit_credit":{"type":"string","enum":["debit","credit"],"title":"Debit Credit"},"amount_cents":{"type":"integer","title":"Amount Cents","description":"Signed so a positive number always means more cost, more owed to the person, or a bigger advance: debit minus credit on expense and advance accounts, credit minus debit on payable accounts."},"matched_by":{"type":"string","enum":["person","name"],"title":"Matched By","description":"person: the line is linked to this roster person. name: only its counterparty name matches (a line written before the link existed)."}},"type":"object","required":["line_id","journal_entry_id","date","ledger_id","ledger_name","component","debit_credit","amount_cents","matched_by"],"title":"PersonLedgerLine","description":"One journal line about the person."},"PersonLedgerMonth":{"properties":{"month":{"type":"string","title":"Month","description":"YYYY-MM"},"components":{"additionalProperties":{"type":"integer"},"type":"object","title":"Components","description":"Cents per component, signed as the lines."},"cost_cents":{"type":"integer","title":"Cost Cents","description":"pay + bonus + burden.","default":0}},"type":"object","required":["month"],"title":"PersonLedgerMonth"},"PersonLedgerResponse":{"properties":{"person_id":{"type":"string","title":"Person Id"},"months":{"items":{"type":"string"},"type":"array","title":"Months","description":"YYYY-MM, oldest first."},"by_month":{"items":{"$ref":"#/components/schemas/PersonLedgerMonth"},"type":"array","title":"By Month"},"totals":{"additionalProperties":{"type":"integer"},"type":"object","title":"Totals","description":"Cents per component over the window."},"cost_cents":{"type":"integer","title":"Cost Cents","description":"pay + bonus + burden over the window.","default":0},"payable_cents":{"type":"integer","title":"Payable Cents","description":"All time: owed to the person on payable accounts.","default":0},"advance_cents":{"type":"integer","title":"Advance Cents","description":"All time: advanced to the person and not yet settled.","default":0},"lines":{"items":{"$ref":"#/components/schemas/PersonLedgerLine"},"type":"array","title":"Lines","description":"Newest first, capped at ``lines_limit``."},"lines_total":{"type":"integer","title":"Lines Total","description":"Lines in the window before the cap.","default":0},"lines_limit":{"type":"integer","title":"Lines Limit"},"unlinked_lines":{"type":"integer","title":"Unlinked Lines","description":"Window lines matched by name only; they link on their next edit.","default":0}},"type":"object","required":["person_id","months","by_month","lines","lines_limit"],"title":"PersonLedgerResponse","description":"What the books say about one person: cost by month and what is owed."},"SuccessEnvelope_PersonLedgerResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/PersonLedgerResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[PersonLedgerResponse]"},"ErrorResponse":{"title":"ErrorResponse","type":"object","description":"Envelope returned by every non-2xx response. Branch on `code` (stable) rather than `message` (human-readable, may change).","required":["error","message","code"],"properties":{"error":{"type":"string","description":"Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`."},"message":{"type":"string","description":"Human-readable explanation, safe to show to end users."},"code":{"type":"string","description":"Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`)."},"request_id":{"type":"string","description":"Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied."},"errors":{"type":"object","additionalProperties":{"type":"string"},"description":"Field-level validation messages keyed by field name. Present on 400/422 validation failures only."}}}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Token","description":"API token authentication. Format: `Bearer dz_...`"}}},"security":[{"BearerAuth":[]}]}