> ## Documentation Index
> Fetch the complete documentation index at: https://docs.finosu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# List Daily Billing Costs

> Retrieve each loan’s charges for one day, for reporting cost per loan alongside your own loan data.

Use `GET /billing/daily-costs` to retrieve one row per loan that had billable activity on a given day: the same charges as the Billing Summary in the client dashboard, broken out by day instead of by month. Loans with no calls, texts, emails, or payments that day are omitted.

The response is scoped to the company associated with your `X-API-Key`. A key belongs to exactly one company, so a lender with several brands makes one request per brand, using that brand's key. Only first-party loans on usage billing are included; a company that is not billed per use receives `400`.

`loanId` is the loan identifier you supplied at enrollment or in your file upload, so rows join directly to your loan records. `customerId` is your customer reference, or the Finosu customer UUID for a customer boarded without one. A typical use is to sum a brand's rows over a week and divide by that week's transfers or funded loans.

## First request

```bash theme={null}
curl --fail-with-body --get 'https://api.finosu.com/billing/daily-costs' \
  --header "X-API-Key: $FINOSU_API_KEY" \
  --data-urlencode 'date=2026-10-27'
```

```json theme={null}
{
  "date": "2026-10-27",
  "currency": "USD",
  "rows": [
    {
      "loanId": "5800001",
      "customerId": "6600001",
      "applicationStatus": "PENDING",
      "callCount": "3.00",
      "callMinutes": "4.00",
      "callSeconds": "179.00",
      "telephonyCost": "0.1200",
      "virtualAgentCost": "0.3282",
      "smsCount": "1.00",
      "smsSegments": "1.00",
      "smsCost": "0.0090",
      "emailCount": "1.00",
      "emailCost": "0.0010",
      "portalCollected": "0.00",
      "externalCollected": "0.00",
      "paymentProcessingFee": "0.0000",
      "totalCost": "0.4582"
    },
    {
      "loanId": "5800002",
      "customerId": "6600002",
      "applicationStatus": "FUNDED",
      "callCount": "1.50",
      "callMinutes": "2.50",
      "callSeconds": "125.00",
      "telephonyCost": "0.0750",
      "virtualAgentCost": "0.2292",
      "smsCount": "0.00",
      "smsSegments": "0.00",
      "smsCost": "0.0000",
      "emailCount": "0.00",
      "emailCost": "0.0000",
      "portalCollected": "150.00",
      "externalCollected": "0.00",
      "paymentProcessingFee": "6.0000",
      "totalCost": "6.3042"
    },
    {
      "loanId": "5800003",
      "customerId": "6600002",
      "applicationStatus": "PENDING",
      "callCount": "0.50",
      "callMinutes": "0.50",
      "callSeconds": "30.00",
      "telephonyCost": "0.0150",
      "virtualAgentCost": "0.0550",
      "smsCount": "0.00",
      "smsSegments": "0.00",
      "smsCost": "0.0000",
      "emailCount": "0.00",
      "emailCost": "0.0000",
      "portalCollected": "0.00",
      "externalCollected": "0.00",
      "paymentProcessingFee": "0.0000",
      "totalCost": "0.0700"
    }
  ],
  "nextCursor": null
}
```

In this example the first loan had three calls (47 seconds, 132 seconds, and one that did not connect), one text, and one email. The second and third loans are two open applications from the same customer. That customer's 95-second scheduled call was placed for the second loan, so it carries the whole call. The customer also called in for 60 seconds, which names no loan, so that call is shared evenly: half on each application. The second loan also had a `$150.00` payment collected through Finosu.

All numeric values are decimal strings, so you can add them without floating-point error. Each row is rounded on its own: counts, minutes, seconds, and collected amounts to 2 decimal places, charges to 4. A shared communication can therefore add up to slightly more or less than its whole; one call shared across three loans shows `callCount` `0.33` on each row, `0.99` in total. `totalCost` is exactly the sum of the row's five charges.

## How charges are calculated

Every call minute carries two charges: telephony and virtual agent. Rates are the ones in your Finosu agreement and are not repeated in the response.

| Charge | Calculation |
| - | - |
| Telephony | Each call with a duration is rounded **up** to the next whole minute, then priced per minute. Calls that did not connect have no duration and no telephony charge, but are counted in `callCount`. |
| Virtual agent | Exact call seconds, priced per minute at the company's tiered virtual-agent rate. See [Daily rows and the monthly bill](#daily-rows-and-the-monthly-bill). |
| SMS | Sent outbound messages only, priced per segment, plus the carrier's per-message fee passed through at cost. |
| Email | Sent emails, priced per email. |
| Payment processing | A percentage of payments collected through Finosu (`portalCollected`). Payments recorded as collected outside Finosu (`externalCollected`) are reported but not charged. |

## Customers with more than one loan

Each scheduled call, text, and email is charged to the loan it was scheduled for, as long as that loan belongs to the same customer and is open on the day. When a customer has more than one loan open, for example two applications, each loan carries only its own outreach.

Any other communication, such as an inbound call, one sent outside a loan's schedule, or one scheduled for a loan that has since closed, is shared evenly across the customer's loans open that day. That is the only reason counts such as `callCount` can be fractional. Payments are recorded against a specific loan and are never shared.

Sharing never changes totals beyond that per-row rounding: the sum of a brand's rows for a day is the brand's full cost for that day, to within a fraction of a cent per shared communication.

## Daily rows and the monthly bill

Summing a month of daily rows reproduces the month's Billing Summary charges, within the limits below.

* **Telephony, SMS, email, and payment processing** are priced per item, so daily amounts add up to the monthly amount.
* **Virtual agent** pricing is tiered on the company's cumulative minutes in the month. Each day is priced at the rate that applied to the minutes used that day, so a day's charge never changes when a later day crosses into a lower tier, and a month of days adds up to the company's monthly tiered total. Within a month that crosses a tier, the Billing Summary applies the month's average rate to every loan, so an individual loan's month can differ slightly from the sum of its days.
* **Communications that name no loan:** a day shares them across the loans open that day, while the monthly Billing Summary shares them across the loans open at any point in the month. If such a customer gains or loses a loan mid-month, that customer's daily rows can differ from the monthly figure by a few cents.
* **Rounding:** each row's charges are rounded to 4 decimal places, and the monthly Billing Summary rounds once per loan. A month of daily rows can differ from the monthly figure by up to `$0.00005` per row for each charge.

## When a day is final

* **Only completed days can be requested.** Today or a future date returns `422`.
* **Calls, texts, and emails** for a day are final once the day has ended in America/New\_York. The carrier fee on a text can arrive a few minutes after the message is sent, so request day `D` after 06:00 America/New\_York on day `D + 1`.
* **Payment fields can change after the day ends.** A bank payment that is later returned no longer counts as collected, which lowers `portalCollected` and `paymentProcessingFee` on the day it was originally collected. Most returns arrive within 2 banking days, but a return the borrower reports as unauthorized can arrive up to 60 days after the payment. To stay current:

  * on each daily pull, re-request the previous 7 days, and
  * once a week, re-request each of the previous 70 days, which covers the 60-day return window plus the gap between weekly pulls,

  replacing your stored rows for each day you re-request.
* **`applicationStatus` is current, not historical.** It is the loan's status when you make the request, so re-requesting an old day can show a loan that has since funded as `FUNDED`.

## Retrieve every page

Rows are ordered by `loanId`, then by Finosu's internal loan identifier to break ties. `limit` defaults to 1000 and accepts 1–1000. When `nextCursor` contains a string, pass that exact value as the next request's `cursor` with the same `date`; a `null` cursor means the day is complete. Treat cursors as opaque and URL-encode them. A day with no activity returns `{"date": "...", "currency": "USD", "rows": [], "nextCursor": null}`.

The endpoint allows 60 requests per 60-second window per company, shared across its API keys. If the quota is exhausted (`429`) or its enforcement is temporarily unavailable (`503`), wait for the `Retry-After` interval before retrying the same page. Successful responses are sent with `Cache-Control: no-store`.

```python theme={null}
import os

import requests

def daily_costs(day: str):
    params = {"date": day}
    while True:
        response = requests.get(
            "https://api.finosu.com/billing/daily-costs",
            params=params,
            headers={"X-API-Key": os.environ["FINOSU_API_KEY"]},
            timeout=60,
        )
        response.raise_for_status()
        body = response.json()
        yield from body["rows"]
        if body["nextCursor"] is None:
            return
        params["cursor"] = body["nextCursor"]
```


## OpenAPI

````yaml GET /billing/daily-costs
openapi: 3.1.0
info:
  title: Finosu API
  description: Finosu API
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://api.finosu.com
security:
  - apiKeyAuth: []
paths:
  /billing/daily-costs:
    get:
      summary: List daily billing costs
      description: >-
        Returns one row per loan with billable activity on a completed
        America/New_York calendar day: calls, texts, emails, and payments,
        priced the same way as the Billing Summary in the client dashboard.
        Scoped to the company of the X-API-Key; a lender with several brands
        calls once per brand key. Only first-party loans on usage billing are
        included. Ordered by loanId, then the Finosu loan UUID. Limited to 60
        requests per 60 seconds per company across all API keys. Exceeded quotas
        return 429; quota-service outages return 503. Both include Retry-After:
        60. Follow nextCursor until null; keep date unchanged.
      operationId: listDailyBillingCosts
      parameters:
        - name: date
          in: query
          required: true
          description: >-
            Calendar day in America/New_York, YYYY-MM-DD. Must be a completed
            day: today or a future date returns 422.
          schema:
            type: string
            format: date
        - name: limit
          in: query
          required: false
          description: Maximum rows per page. Default 1000; range 1–1000.
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: cursor
          in: query
          required: false
          description: >-
            Opaque nextCursor from the preceding response. Keep the same company
            and date.
          schema:
            type: string
            minLength: 1
            maxLength: 2048
      responses:
        '200':
          description: A page of per-loan daily costs. nextCursor is null on the last page.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DailyCostsResponse'
        '400':
          description: The company has no billing configuration, or is not billed per use.
          content:
            application/json:
              schema:
                type: object
                required:
                  - detail
                properties:
                  detail:
                    type: string
        '401':
          description: Missing, invalid, inactive, deleted, or empty API key.
          content:
            application/json:
              schema:
                type: object
                required:
                  - detail
                properties:
                  detail:
                    type: string
        '422':
          description: >-
            Missing, malformed, current, or future date; or an invalid cursor or
            one issued for a different company or date.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
        '429':
          description: Company quota exceeded. Retry after the indicated number of seconds.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
                example: 60
            Cache-Control:
              schema:
                type: string
                const: no-store
          content:
            application/json:
              schema:
                type: object
                required:
                  - detail
                properties:
                  detail:
                    type: string
        '500':
          description: Unexpected internal error.
        '503':
          description: >-
            Quota verification is unavailable. Retry after the indicated number
            of seconds.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
                example: 60
            Cache-Control:
              schema:
                type: string
                const: no-store
          content:
            application/json:
              schema:
                type: object
                required:
                  - detail
                properties:
                  detail:
                    type: string
      security:
        - apiKeyAuth: []
components:
  schemas:
    DailyCostsResponse:
      type: object
      required:
        - date
        - currency
        - rows
        - nextCursor
      properties:
        date:
          type: string
          format: date
          description: The requested day, America/New_York.
        currency:
          type: string
          const: USD
        rows:
          type: array
          items:
            $ref: '#/components/schemas/DailyLoanCost'
        nextCursor:
          type:
            - string
            - 'null'
          description: Opaque continuation cursor, or null when no more rows remain.
    ValidationErrorResponse:
      type: object
      required:
        - detail
      properties:
        detail:
          description: >-
            Application validation returns a message; framework validation
            returns an array of field errors.
          anyOf:
            - type: string
            - type: array
              items:
                $ref: '#/components/schemas/ValidationError'
    DailyLoanCost:
      type: object
      description: >-
        One loan's charges for one America/New_York calendar day. Numeric values
        are decimal strings: counts, minutes, seconds, and collected amounts
        have 2 decimal places; charges have 4.
      required:
        - loanId
        - customerId
        - applicationStatus
        - callCount
        - callMinutes
        - callSeconds
        - telephonyCost
        - virtualAgentCost
        - smsCount
        - smsSegments
        - smsCost
        - emailCount
        - emailCost
        - portalCollected
        - externalCollected
        - paymentProcessingFee
        - totalCost
      properties:
        loanId:
          type: string
          description: 'The loan''s external reference: the loan identifier you supplied.'
          example: '5800001'
        customerId:
          type: string
          description: >-
            The customer's external reference, or the Finosu customer UUID when
            none is stored.
          example: '6600001'
        applicationStatus:
          type: string
          enum:
            - PENDING
            - APPROVED
            - FUNDED
            - WITHDRAWN
            - REJECTED
          description: The loan's application status when the request is made, not on date.
        callCount:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            Calls placed, including calls that did not connect. Charged to the
            loan it was scheduled for when that loan is one of the customer's
            loans open that day; otherwise shared evenly across those loans.
          example: '3.00'
        callMinutes:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            Billed telephony minutes: each call rounded up to the next whole
            minute.
          example: '4.00'
        callSeconds:
          type: string
          pattern: ^-?\d+\.\d+$
          description: Exact call seconds, the basis for virtualAgentCost.
          example: '179.00'
        telephonyCost:
          type: string
          pattern: ^-?\d+\.\d+$
          description: callMinutes priced at the telephony rate.
          example: '0.1200'
        virtualAgentCost:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            callSeconds priced at the company's tiered virtual-agent rate for
            the month to date.
          example: '0.3282'
        smsCount:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            Sent outbound texts. Charged to the loan it was scheduled for when
            that loan is one of the customer's loans open that day; otherwise
            shared evenly across those loans.
          example: '1.00'
        smsSegments:
          type: string
          pattern: ^-?\d+\.\d+$
          description: Billed SMS segments. A long message is sent as several segments.
          example: '1.00'
        smsCost:
          type: string
          pattern: ^-?\d+\.\d+$
          description: Segment charges plus carrier fees passed through at cost.
          example: '0.0090'
        emailCount:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            Sent emails. Charged to the loan it was scheduled for when that loan
            is one of the customer's loans open that day; otherwise shared
            evenly across those loans.
          example: '1.00'
        emailCost:
          type: string
          pattern: ^-?\d+\.\d+$
          description: emailCount priced at the email rate.
          example: '0.0010'
        portalCollected:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            Successful payments collected through Finosu on date. Decreases if a
            payment is later returned.
          example: '0.00'
        externalCollected:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            Successful payments recorded as collected outside Finosu after
            placement. Not charged.
          example: '0.00'
        paymentProcessingFee:
          type: string
          pattern: ^-?\d+\.\d+$
          description: portalCollected multiplied by the company's payment-processing rate.
          example: '0.0000'
        totalCost:
          type: string
          pattern: ^-?\d+\.\d+$
          description: >-
            telephonyCost + virtualAgentCost + smsCost + emailCost +
            paymentProcessingFee.
          example: '0.4582'
    ValidationError:
      type: object
      required:
        - loc
        - msg
        - type
      properties:
        loc:
          type: array
          items:
            anyOf:
              - type: string
              - type: integer
        msg:
          type: string
        type:
          type: string
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.