Recurring schedule reference
Adding a schedule object to the expense creation payload turns a one-time expense
into a recurring template. The engine generates virtual instances automatically for each month view.
Schedule object fields
| Field | Type | Default | Description |
|---|---|---|---|
frequency | string | — | Required. One of: once, daily, weekly, monthly, quarterly, yearly. |
startDate | string | integer | — | Required. ISO date ("2026-03-01") or Unix seconds (1740787200). |
endDate | string | integer | none | Hard end date. Cannot be combined with endAfter. |
dayOfMonth | integer | none | Day of month (1–31). Used with monthly / quarterly. |
dayOfWeek | integer | none | Day of week (0 = Sunday … 6 = Saturday). Used with weekly or monthly+weekOfMonth. |
daysOfWeek | integer[] | none | Multiple days (e.g. [1, 3, 5] = Mon/Wed/Fri). weekly only. |
weekOfMonth | integer | none | Week number (1–5). Requires dayOfWeek. Used with monthly / quarterly. |
interval | integer | 1 | Repeat every N periods (1–100). E.g. 2 with weekly = every 2 weeks. |
endAfter | object | none | End condition. Cannot be combined with endDate. See below. |
timezone | string | "Europe/Warsaw" | IANA timezone for occurrence calculation. |
endAfter object
| type | value | Description |
|---|---|---|
"count" | integer (1–1000) | Stop after N total occurrences. |
"date" | ISO date or Unix seconds | Stop on/after this date. |
End conditions are mutually exclusive
endDate or endAfter, but not both.
Omit both for an open-ended (infinite) recurring schedule.
Required fields by frequency
| frequency | Required extras | Allowed optional | Forbidden |
|---|---|---|---|
once | none | none | dayOfMonth, dayOfWeek, daysOfWeek, weekOfMonth, interval ≠ 1 |
daily | none | interval | dayOfMonth, dayOfWeek, daysOfWeek, weekOfMonth |
weekly | dayOfWeek or daysOfWeek | interval | dayOfMonth, weekOfMonth |
monthly | dayOfMonth or (weekOfMonth + dayOfWeek) | interval | daysOfWeek |
quarterly | dayOfMonth or (weekOfMonth + dayOfWeek) | interval | daysOfWeek |
yearly | none (uses startDate) | interval | daysOfWeek |
weekOfMonth always requires dayOfWeek
weekOfMonth and dayOfWeek.
frequency: once
A single scheduled occurrence at startDate. Useful for a future-dated expense
that should appear on its due date.
curl -X POST https://app.figa.io/api/v1/expenses \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "Annual insurance premium",
"amount": 240000,
"categoryInput": "Insurance",
"schedule": {
"frequency": "once",
"startDate": "2026-06-15"
}
}' frequency: daily
Every day
"schedule": {
"frequency": "daily",
"startDate": "2026-03-01"
} Every 3 days
"schedule": {
"frequency": "daily",
"startDate": "2026-03-01",
"interval": 3
} Every day for 30 days
"schedule": {
"frequency": "daily",
"startDate": "2026-03-01",
"endAfter": { "type": "count", "value": 30 }
} Every day until end of year
"schedule": {
"frequency": "daily",
"startDate": "2026-03-01",
"endDate": "2026-12-31"
} frequency: weekly
Every Friday
"schedule": {
"frequency": "weekly",
"startDate": "2026-03-06",
"dayOfWeek": 5
} dayOfWeek values
0 = Sunday, 1 = Monday, 2 = Tuesday,
3 = Wednesday, 4 = Thursday, 5 = Friday,
6 = Saturday.
Every other Monday
"schedule": {
"frequency": "weekly",
"startDate": "2026-03-02",
"dayOfWeek": 1,
"interval": 2
} Monday, Wednesday, Friday every week
"schedule": {
"frequency": "weekly",
"startDate": "2026-03-02",
"daysOfWeek": [1, 3, 5]
} Tuesday and Thursday, every 2 weeks, 20 occurrences
"schedule": {
"frequency": "weekly",
"startDate": "2026-03-03",
"daysOfWeek": [2, 4],
"interval": 2,
"endAfter": { "type": "count", "value": 20 }
} Full curl — weekly team lunch
curl -X POST https://app.figa.io/api/v1/expenses \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "Team lunch",
"amount": 15000,
"categoryInput": "Food",
"recipientInput": "Pizza Place",
"schedule": {
"frequency": "weekly",
"startDate": "2026-03-06",
"dayOfWeek": 5
}
}' frequency: monthly
1st of every month (rent, subscriptions)
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-01",
"dayOfMonth": 1
} 15th of every month
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-15",
"dayOfMonth": 15
} Last day of month (dayOfMonth: 31)
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-31",
"dayOfMonth": 31
} dayOfMonth: 31 in short months
dayOfMonth exceeds the number of days in a month (e.g. 31 in February),
the occurrence is placed on the last day of that month.
Every other month on the 10th
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-10",
"dayOfMonth": 10,
"interval": 2
} First Monday of every month
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-06",
"weekOfMonth": 1,
"dayOfWeek": 1
} Third Friday of every month
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-16",
"weekOfMonth": 3,
"dayOfWeek": 5
} 12 monthly installments (loan repayment)
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-01",
"dayOfMonth": 1,
"endAfter": { "type": "count", "value": 12 }
} Monthly until December 2027
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-01",
"dayOfMonth": 1,
"endDate": "2027-12-31"
} Full curl — monthly rent
curl -X POST https://app.figa.io/api/v1/expenses \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "Office rent",
"amount": 420000,
"categoryInput": "Housing",
"recipientInput": "WeWork",
"description": "Monthly office lease",
"currency": "PLN",
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-01",
"dayOfMonth": 1
}
}' Full curl — 36 installments (phone lease)
curl -X POST https://app.figa.io/api/v1/expenses \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "iPhone lease",
"amount": 12500,
"categoryInput": "Equipment",
"recipientInput": "Apple",
"schedule": {
"frequency": "monthly",
"startDate": "2026-02-15",
"dayOfMonth": 15,
"endAfter": { "type": "count", "value": 36 }
}
}' frequency: quarterly
1st of each quarter
"schedule": {
"frequency": "quarterly",
"startDate": "2026-01-01",
"dayOfMonth": 1
} 15th of each quarter
"schedule": {
"frequency": "quarterly",
"startDate": "2026-01-15",
"dayOfMonth": 15
} First Monday of each quarter
"schedule": {
"frequency": "quarterly",
"startDate": "2026-01-05",
"weekOfMonth": 1,
"dayOfWeek": 1
} Full curl — quarterly tax advance
curl -X POST https://app.figa.io/api/v1/expenses \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "VAT advance payment",
"amount": 850000,
"categoryInput": "Tax",
"recipientInput": "Urząd Skarbowy",
"schedule": {
"frequency": "quarterly",
"startDate": "2026-01-25",
"dayOfMonth": 25
}
}' frequency: yearly
Yearly on start date anniversary
"schedule": {
"frequency": "yearly",
"startDate": "2026-06-15"
}
For yearly, the recurrence date is derived from startDate.
No additional fields (dayOfMonth, dayOfWeek) are required.
Every 2 years
"schedule": {
"frequency": "yearly",
"startDate": "2026-06-15",
"interval": 2
} Full curl — yearly domain renewal
curl -X POST https://app.figa.io/api/v1/expenses \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "figa.io domain renewal",
"amount": 4500,
"categoryInput": "Infrastructure",
"recipientInput": "Cloudflare",
"currency": "USD",
"schedule": {
"frequency": "yearly",
"startDate": "2026-09-12"
}
}' Managing recurring expenses
Read schedule details
curl -X GET https://app.figa.io/api/v1/expenses/{expenseId} \
-H "x-api-key: et_live_abc123..."
Returns the full expense object with schedule, occurrences array,
and stats (totalOccurrences, paidOccurrences, progress, etc.).
Read a single occurrence
curl -X GET "https://app.figa.io/api/v1/expenses/{expenseId}?occurrence=1740787200" \
-H "x-api-key: et_live_abc123..." Pass the occurrence's scheduled Unix timestamp to get that specific instance.
Change schedule for entire series
curl -X PUT https://app.figa.io/api/v1/expenses/{expenseId} \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"schedule": {
"frequency": "monthly",
"startDate": "2026-01-05",
"dayOfMonth": 5
},
"editScope": "ALL_INSTANCES"
}' Update amount for this + future occurrences
curl -X PUT https://app.figa.io/api/v1/expenses/{expenseId} \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"amount": 450000,
"editScope": "FUTURE_INSTANCES"
}' Override a single occurrence
curl -X PUT https://app.figa.io/api/v1/expenses/{expenseId} \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"amount": 500000,
"description": "Increased rent for March",
"editScope": "THIS_INSTANCE"
}' Skip an occurrence
scheduledDate accepts Unix seconds or ISO date YYYY-MM-DD.
Using Unix timestamp
curl -X POST https://app.figa.io/api/v1/expenses/{expenseId}/skip/toggle \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{"scheduledDate": 1740787200}' Using ISO date (recommended)
curl -X POST https://app.figa.io/api/v1/expenses/{expenseId}/skip/toggle \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{"scheduledDate": "2026-03-30"}'
Call again with the same scheduledDate to restore a skipped occurrence.
Only unpaid instances can be skipped. If occurrence is not found, API returns 404.
Convert recurring to one-time
curl -X PUT https://app.figa.io/api/v1/expenses/{expenseId} \
-H "x-api-key: et_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"schedule": null,
"editScope": "ALL_INSTANCES"
}' Delete single occurrence
curl -X DELETE "https://app.figa.io/api/v1/expenses/{expenseId}?editScope=THIS_INSTANCE" \
-H "x-api-key: et_live_abc123..." Delete entire series
curl -X DELETE "https://app.figa.io/api/v1/expenses/{expenseId}?editScope=ALL_INSTANCES" \
-H "x-api-key: et_live_abc123..." editScope reference
When updating (PUT) or deleting (DELETE) a recurring expense,
editScope determines which occurrences are affected:
| Value | PUT effect | DELETE effect |
|---|---|---|
THIS_INSTANCE | Materializes and overrides only this occurrence. | Removes only this occurrence. |
FUTURE_INSTANCES | Applies changes to this and all future occurrences. | Removes this and all future occurrences. |
ALL_INSTANCES | Updates the template (all past + future). | Deletes the entire recurring series. |
editScope is for recurring expenses only
editScope. It is ignored for non-recurring expenses.
Quick reference — common patterns
| Use case | schedule JSON |
|---|---|
| Monthly rent on 1st | { "frequency": "monthly", "startDate": "2026-01-01", "dayOfMonth": 1 } |
| Weekly Friday coffee | { "frequency": "weekly", "startDate": "2026-01-02", "dayOfWeek": 5 } |
| Quarterly tax (25th) | { "frequency": "quarterly", "startDate": "2026-01-25", "dayOfMonth": 25 } |
| Yearly renewal | { "frequency": "yearly", "startDate": "2026-09-12" } |
| Bi-weekly Mon payroll | { "frequency": "weekly", "startDate": "2026-01-05", "dayOfWeek": 1, "interval": 2 } |
| Mon/Wed/Fri gym | { "frequency": "weekly", "startDate": "2026-01-05", "daysOfWeek": [1, 3, 5] } |
| 1st Monday of month | { "frequency": "monthly", "startDate": "2026-01-05", "weekOfMonth": 1, "dayOfWeek": 1 } |
| 12 installments | { "frequency": "monthly", "startDate": "2026-01-01", "dayOfMonth": 1, "endAfter": { "type": "count", "value": 12 } } |
| Daily until end of year | { "frequency": "daily", "startDate": "2026-01-01", "endDate": "2026-12-31" } |
| Every 3 days, 30 times | { "frequency": "daily", "startDate": "2026-01-01", "interval": 3, "endAfter": { "type": "count", "value": 30 } } |