{"openapi":"3.1.0","info":{"title":"GET /api/v1/credit/programs/{program_id}/import-batches","version":"1.0.0","description":"A program's loan files, newest first"},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/credit/programs/{program_id}/import-batches":{"get":{"tags":["credit"],"summary":"A program's loan files, newest first","description":"Every loan file staged on the program, newest first, paged. Operator action: an API token receives `403`.","operationId":"credit_import_list_batches","parameters":[{"name":"program_id","in":"path","required":true,"schema":{"type":"string","title":"Program Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Page size (1-100).","default":20,"title":"Limit"},"description":"Page size (1-100)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`next_cursor` from the previous page.","title":"Cursor"},"description":"`next_cursor` from the previous page."},{"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_ImportBatchPage_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"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":"credit_import_list_batches_api_v1_credit_programs__program_id__import_batches_get"}}},"components":{"schemas":{"ImportBatchPage":{"properties":{"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass back as `cursor` for the next page. Null on the last."},"has_next":{"type":"boolean","title":"Has Next","description":"Another page follows. Looked up one row past the page, so a full last page is not reported as more.","default":false},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit","description":"The page size the list was read with."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Row count; present only with `include_total_count=true`."},"items":{"items":{"$ref":"#/components/schemas/ImportBatchResponse"},"type":"array","title":"Items","description":"The batches on this page."}},"type":"object","title":"ImportBatchPage","description":"A page of a program's import batches, newest first."},"ImportBatchResponse":{"properties":{"staging_id":{"type":"string","title":"Staging Id","description":"The batch id. Also the report id."},"program_id":{"type":"string","title":"Program Id","description":"The program the file is for."},"filename":{"type":"string","title":"Filename","description":"The file's name as uploaded."},"sha256":{"type":"string","title":"Sha256","description":"SHA-256 of the file as uploaded."},"row_count":{"type":"integer","title":"Row Count","description":"Rows in the file, header excluded."},"status":{"type":"string","enum":["parsed","running","dry_run","applied","failed","expired"],"title":"Status","description":"parsed, running (a run is in progress), dry_run, applied, failed (control totals did not tie, or the run stopped: see `run.error`) or expired."},"amounts_in":{"type":"string","enum":["dollars","cents"],"title":"Amounts In","description":"The unit of every money column."},"line_key_field":{"anyOf":[{"type":"string","enum":["external_line_id","external_merchant_id"]},{"type":"null"}],"title":"Line Key Field","description":"Which key groups rows into lines: `external_line_id` when mapped, else `external_merchant_id`. Null when neither is mapped."},"mapping":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object","title":"Mapping","description":"Target field → source column in force."},"totals":{"$ref":"#/components/schemas/ImportBatchTotals","description":"What the file holds under the mapping in force."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the file was staged (UTC)."},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"Seven days after staging. An unapplied batch is refused after it."},"applied_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Applied At","description":"When the file was written to the book."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"Who staged the file."},"last_run":{"anyOf":[{"$ref":"#/components/schemas/ImportRunSummary"},{"type":"null"}],"description":"The last finished dry run or apply, from its report; null before the first."},"run":{"anyOf":[{"$ref":"#/components/schemas/ImportRun"},{"type":"null"}],"description":"The current or last run, with its progress: poll this while `status` is `running`. Null before the first."},"result":{"anyOf":[{"$ref":"#/components/schemas/ProgramLoanImportResponse"},{"type":"null"}],"description":"Once the last run has finished: the body the inline call returns (per-line results, totals against the control totals, `applied`, `report_id`). Null while a run is in progress, after a run that stopped, and in the list."}},"type":"object","required":["staging_id","program_id","filename","sha256","row_count","status","amounts_in","created_at","expires_at"],"title":"ImportBatchResponse","description":"A staged loan file: identity, mapping, status and totals."},"ImportBatchTotals":{"properties":{"row_count":{"type":"integer","title":"Row Count","description":"Rows in the file.","default":0},"importable_count":{"type":"integer","title":"Importable Count","description":"Rows with no error.","default":0},"error_row_count":{"type":"integer","title":"Error Row Count","description":"Rows that will be rejected.","default":0},"warning_count":{"type":"integer","title":"Warning Count","description":"Warnings across every row.","default":0},"unassigned_row_count":{"type":"integer","title":"Unassigned Row Count","description":"Rows with no line key, so on no line.","default":0},"line_count":{"type":"integer","title":"Line Count","description":"Distinct line keys in the file.","default":0},"unmatched_line_count":{"type":"integer","title":"Unmatched Line Count","description":"Line keys with no line on the program.","default":0},"principal_cents":{"type":"integer","title":"Principal Cents","description":"Original principal over importable rows.","default":0},"outstanding_cents":{"type":"integer","title":"Outstanding Cents","description":"Outstanding over importable rows.","default":0}},"type":"object","title":"ImportBatchTotals","description":"What a staged file holds under its current mapping."},"ImportExpectedTotals":{"properties":{"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count","description":"Expected row count."},"principal_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Principal Cents","description":"Expected principal."},"outstanding_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Outstanding Cents","description":"Expected outstanding."}},"type":"object","title":"ImportExpectedTotals","description":"The control totals the operator gave from the partner's book."},"ImportLineDefaults":{"properties":{"credit_limit_cents":{"type":"integer","minimum":0.0,"title":"Credit Limit Cents","description":"The new line's limit."},"term_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Term Days","description":"Defaults to the program's first term."},"start_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Start Date","description":"The signing date of the merchant's agreement."}},"additionalProperties":false,"type":"object","required":["credit_limit_cents"],"title":"ImportLineDefaults","description":"Terms for a line the import opens for a key the program does not have."},"ImportLineResult":{"properties":{"line_key":{"type":"string","title":"Line Key","description":"The line key."},"credit_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Credit Line Id","description":"The line; null when none could be found or opened."},"created":{"type":"boolean","title":"Created","description":"The line was opened by this import.","default":false},"imported":{"type":"integer","title":"Imported","description":"New loans.","default":0},"duplicates":{"type":"integer","title":"Duplicates","description":"Rows whose loan was already on the line.","default":0},"rejected":{"type":"integer","title":"Rejected","description":"Rows that did not load.","default":0},"principal_cents":{"type":"integer","title":"Principal Cents","description":"Original principal over rows that loaded.","default":0},"outstanding_cents":{"type":"integer","title":"Outstanding Cents","description":"Outstanding over rows that loaded.","default":0},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why the whole line did not load: no such line, or opening it was refused."}},"type":"object","required":["line_key"],"title":"ImportLineResult","description":"What the import did on one line."},"ImportRowRejection":{"properties":{"row_number":{"type":"integer","title":"Row Number","description":"Position in the file, from 1."},"line_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line Key","description":"The row's line key."},"external_settlement_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Settlement Id","description":"The row's issuer transaction id, when it has one."},"reason":{"type":"string","title":"Reason","description":"Why it was rejected."}},"type":"object","required":["row_number","reason"],"title":"ImportRowRejection","description":"A row that did not load, and why."},"ImportRun":{"properties":{"id":{"type":"string","title":"Id","description":"The run. A new start gets a new id."},"kind":{"type":"string","enum":["dry_run","apply"],"title":"Kind","description":"`dry_run` or `apply`."},"mode":{"type":"string","enum":["sync","async"],"title":"Mode","description":"`sync`: ran in the request. `async`: ran as a background job."},"started_at":{"type":"string","format":"date-time","title":"Started At","description":"When it was started (UTC)."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When it finished or stopped; null while running."},"heartbeat_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Heartbeat At","description":"The job's last sign of life (UTC)."},"elapsed_seconds":{"type":"integer","title":"Elapsed Seconds","description":"Seconds from start to finish, or to now while it runs."},"stale":{"type":"boolean","title":"Stale","description":"Still `running`, but the job has not reported for 10 minutes: its worker stopped. Starting the batch again takes it over.","default":false},"started_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started By","description":"Who started it."},"inputs":{"$ref":"#/components/schemas/ImportRunInputs","description":"What the run was started with: control totals, as-of date, line options."},"progress":{"$ref":"#/components/schemas/ImportRunProgress","description":"How far it got: rows and lines done of the total, and the phase."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why the run stopped before finishing (a crash, a timeout, or a run taken over). Nothing was written; run it again."}},"type":"object","required":["id","kind","mode","started_at","elapsed_seconds","progress"],"title":"ImportRun","description":"A batch's current or last dry run or apply."},"ImportRunInputs":{"properties":{"as_of":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"As Of","description":"Loan status assessed as at this date; null is today."},"expected_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expected Count","description":"Control count."},"expected_principal_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expected Principal Cents","description":"Control principal."},"expected_outstanding_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expected Outstanding Cents","description":"Control outstanding."},"create_missing_lines":{"type":"boolean","title":"Create Missing Lines","description":"Lines are opened for keys the program lacks.","default":false},"line_defaults":{"anyOf":[{"$ref":"#/components/schemas/ImportLineDefaults"},{"type":"null"}],"description":"Terms for the lines the run opens."},"allow_cross_line_duplicates":{"type":"boolean","title":"Allow Cross Line Duplicates","description":"Rows repeating a transaction id held on another line load.","default":false}},"type":"object","title":"ImportRunInputs","description":"What the run was asked to do: the options of the request that started it."},"ImportRunProgress":{"properties":{"phase":{"type":"string","enum":["queued","loading","importing","checking","saving","done","failed"],"title":"Phase","description":"`queued` (waiting for a worker), `loading` (reading the staged rows), `importing` (line by line), `checking` (reading the book back for the report), `saving`, then `done`, or `failed`."},"rows_done":{"type":"integer","title":"Rows Done","description":"Rows processed so far.","default":0},"rows_total":{"type":"integer","title":"Rows Total","description":"Rows in the file.","default":0},"lines_done":{"type":"integer","title":"Lines Done","description":"Lines processed so far.","default":0},"lines_total":{"type":"integer","title":"Lines Total","description":"Distinct line keys in the file.","default":0}},"type":"object","required":["phase"],"title":"ImportRunProgress","description":"How far a dry run or apply has got."},"ImportRunSummary":{"properties":{"dry_run":{"type":"boolean","title":"Dry Run","description":"The run was a dry run."},"applied":{"type":"boolean","title":"Applied","description":"The run wrote to the book."},"run_at":{"type":"string","format":"date-time","title":"Run At","description":"When it ran (UTC)."},"run_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Run By","description":"Who ran it."},"mismatches":{"items":{"type":"string"},"type":"array","title":"Mismatches","description":"Everything that did not tie: control totals, then lines. After an apply the control totals refused, a last entry says nothing was written and what to do."}},"type":"object","required":["dry_run","applied","run_at"],"title":"ImportRunSummary","description":"The last dry run or apply of a batch."},"ImportTotals":{"properties":{"count":{"type":"integer","title":"Count","description":"Rows that loaded: new plus duplicates.","default":0},"principal_cents":{"type":"integer","title":"Principal Cents","description":"Original principal.","default":0},"outstanding_cents":{"type":"integer","title":"Outstanding Cents","description":"Outstanding.","default":0}},"type":"object","title":"ImportTotals","description":"Counts and money over the rows that loaded (or would)."},"ImportWarning":{"properties":{"code":{"type":"string","title":"Code","description":"`no_interest_ceiling`: the program has no ceiling on a loan's interest, and the ceiling is frozen onto each loan when it is created, so these loans stay uncapped for good. `repeats_id_on_other_line`: the row loaded although its transaction id is already on another line."},"message":{"type":"string","title":"Message","description":"What it means and what to do, in words."},"row_number":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Number","description":"Position in the file, from 1; null for the run."},"line_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line Key","description":"The row's line key."},"external_settlement_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Settlement Id","description":"The row's issuer transaction id."}},"type":"object","required":["code","message"],"title":"ImportWarning","description":"Something the operator should read before applying; the run did not stop."},"ProgramLoanImportResponse":{"properties":{"staging_id":{"type":"string","title":"Staging Id","description":"The batch."},"report_id":{"type":"string","title":"Report Id","description":"The import report: `GET /credit/import-batches/{id}/report`."},"dry_run":{"type":"boolean","title":"Dry Run","description":"Nothing was meant to be written."},"applied":{"type":"boolean","title":"Applied","description":"Every line was written together. False on a dry run, and when a control total did not match: then nothing was written."},"as_of":{"type":"string","format":"date","title":"As Of","description":"The date loan status was assessed as at."},"lines":{"items":{"$ref":"#/components/schemas/ImportLineResult"},"type":"array","title":"Lines","description":"What the run did on each line."},"lines_created":{"type":"integer","title":"Lines Created","description":"Lines opened by the import.","default":0},"imported":{"type":"integer","title":"Imported","description":"New loans over every line.","default":0},"duplicates":{"type":"integer","title":"Duplicates","description":"Duplicates over every line.","default":0},"rejected":{"type":"integer","title":"Rejected","description":"Rejected rows over the file.","default":0},"totals":{"$ref":"#/components/schemas/ImportTotals","description":"What loaded (or would): checked against `expected`."},"expected":{"$ref":"#/components/schemas/ImportExpectedTotals","description":"The control totals the run was given."},"mismatches":{"items":{"type":"string"},"type":"array","title":"Mismatches","description":"Each control total that did not match the file, in words. On an apply they refused, a last entry says that nothing was written and what to do: fix or leave out the rejected rows, or correct the totals, then run the dry run again."},"rejections":{"items":{"$ref":"#/components/schemas/ImportRowRejection"},"type":"array","title":"Rejections","description":"Rejected rows, the first 200; `rejected` counts them all. Every one is in the report (`GET /credit/import-batches/{id}/report`), which is available after a dry run too."},"warnings":{"items":{"$ref":"#/components/schemas/ImportWarning"},"type":"array","title":"Warnings","description":"Things to read before applying: run-level warnings first (a program with no interest ceiling), then rows. The first 200; `warning_count` has them all."},"warning_count":{"type":"integer","title":"Warning Count","description":"Every warning of the run.","default":0},"dry_run_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dry Run Token","description":"On a dry run: a digest of the batch, its mapping and this run's inputs (with `as_of` resolved). Send it on the apply as `dry_run_token` to apply exactly what this dry run checked. Null on an apply."}},"type":"object","required":["staging_id","report_id","dry_run","applied","as_of"],"title":"ProgramLoanImportResponse","description":"The outcome of a program-level dry run or apply."},"SuccessEnvelope_ImportBatchPage_":{"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/ImportBatchPage"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ImportBatchPage]"},"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":[]}]}