Loan Schedule API
Generate precise amortisation schedules with odd-day interest handling, 360/365-day basis, and API key authentication.
Authentication
All endpoints except GET /api/health require an API key when the
API_KEYS environment variable is set.
If API_KEYS is not set, auth is disabled (useful for local development).
Generate a key (run once on your server)
python app.py --genkey
# Output:
Raw key (share with clients): ls_a1b2c3d4e5f6...
Hash (add to API_KEYS env): 9f8e7d6c5b4a...
Configure on Digital Ocean App Platform
# App Platform → Settings → Environment Variables API_KEYS = 9f8e7d6c5b4a... # Multiple keys: comma-separated hashes API_KEYS = 9f8e7d6c...,ab12cd34...,ef56gh78...
HTTP status codes
| Code | Meaning |
|---|---|
| 401 | No key provided |
| 403 | Key invalid |
| 200 | Authenticated and successful |
POST
/api/schedule
Requires API key
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
| loan_amount | number | required | Principal loan amount |
| base_apr | number | required | APR as a percentage (e.g. 600 for 600%) |
| num_payments | integer | required | Total payments (2–1200) |
| payment_frequency | string | required | bi-weekly, weekly, monthly, monthly-28, or raw day count |
| loan_date | string | required | YYYY-MM-DD or MM/DD/YYYY |
| first_payment_date | string | required | Must be after loan_date |
| day_count_basis | integer | optional | 360 (default) or 365 |
Example Request
"loan_amount": 675, "base_apr": 600, "num_payments": 20, "payment_frequency": "bi-weekly", "loan_date": "2026-03-26", "first_payment_date": "2026-04-03", "day_count_basis": 360
Response Structure
{
"inputs": { /* parsed inputs + odd_days, payments_per_year */ },
"derived": {
"daily_rate": "0.01666667",
"periodic_rate": "0.23076923",
"odd_day_interest": "90.00",
"annuity_factor": "4.24949...",
"standard_payment": "145.73",
"last_payment": "145.49"
},
"summary": { "finance_charge": "2239.36", "total_payments": "2914.36", ... },
"schedule": [
{
"payment_number": 1,
"due_date": "2026-04-03",
"due_date_display": "04/03/2026",
"balance_in": "675.00",
"interest": "90.00",
"principal": "55.73",
"payment": "145.73",
"accum_principal": "55.73",
"accum_interest": "90.00",
"balance_out": "619.27"
}
]
}
GET
/api/health
No auth required
{ "status": "ok", "service": "loan-schedule-api", "auth_enabled": true }
Try it out
API Key (leave blank if auth is disabled)
Request Body
Calculating…
Response
curl Examples
With API key
curl -X POST https://your-app.ondigitalocean.app/api/schedule \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_RAW_KEY" \
-d '{
"loan_amount": 675,
"base_apr": 600,
"num_payments": 20,
"payment_frequency": "bi-weekly",
"loan_date": "2026-03-26",
"first_payment_date": "2026-04-03"
}'
Python requests
import requests
resp = requests.post(
"https://your-app.ondigitalocean.app/api/schedule",
headers={"X-API-Key": "YOUR_RAW_KEY"},
json={
"loan_amount": 675,
"base_apr": 600,
"num_payments": 20,
"payment_frequency": "bi-weekly",
"loan_date": "2026-03-26",
"first_payment_date": "2026-04-03",
}
)
data = resp.json()
for row in data["schedule"]:
print(row["due_date_display"], row["payment"], row["balance_out"])