Skip to content
Sad Subscription Analytics
Menu

CSV import

In SadAnalytics Pro, the Import CSV modal on the Manual Payments page will load many subscriptions and one-off payments at once from a spreadsheet. This page describes how it works, so you know what to expect.

Accepted columns

The importer reads eleven columns by header name; column order and letter case do not matter, and any other column is ignored.

ColumnRequiredFormatExample
typeYes"subscription" or "one_off"subscription
emailYesA valid email address[email protected]
nameNoFree textJane Doe
planNoFree text, up to 255 charactersGold plan
amountYesA plain number, dot decimal, optional comma thousands separator19.99
currencyNo3-letter code; blank becomes USDUSD
intervalSubscriptions onlymonthly, quarterly, half-yearly, annual, or custommonthly
custom_daysOnly when interval is customA whole number of days, 1 or more45
dateYesYYYY-MM-DD2026-01-15
statusNo (subscriptions only)"active" or "cancelled"; blank means activeactive
cancelled_dateOnly when status is cancelledYYYY-MM-DD, not before date, not after today (UTC)2026-04-20

Accepted statuses, and cancelled rows

A subscription row's status must be "active" or "cancelled", in any letter case (or blank, which means active); other spellings, including the American "canceled", are rejected. One-off rows are never status-checked.

Duplicate detection

Each row is fingerprinted from its type, email, amount, currency, date and plan or item text. A row matching a record already on file, or an earlier row in the same file, is skipped and counted as a duplicate. Re-importing the same file a second time adds nothing.

Dry run versus import

Preview runs the whole import as a dry run, writing nothing, and reports how many rows would import, how many are duplicates, how many are the template's own example rows, and how many have errors. When a duplicate row asks for a cancellation the stored subscription does not have, a fifth count appears: Already imported, cancellation not applied.

Import runs the same classification for real, writes every valid row in one pass, then reports the same counts for what actually happened.

The template and its example rows

Download CSV template gets you manual-payments-template.csv: the eleven column headers plus four filled-in example rows (one recurring subscription, one with a custom billing interval, one cancelled subscription, and one one-off payment).

Any row that is byte-for-byte identical to an example row is ignored, so you can leave them in place while you add real rows above or below them.

Row error messages

MessageWhen it appears
Type must be "subscription" or "one_off".The type column is missing or not one of those two words.
A valid email is required.The email column is blank or not a real email address.
Amount must be a plain number such as 19.99 or 1,999.00 (use a dot for the decimal point).The amount uses a comma decimal, a currency symbol, or a sign.
Amount must be greater than zero.The amount is blank or zero.
Date must be in YYYY-MM-DD format.The date is missing or not a real calendar date in that format.
Interval must be monthly, quarterly, half-yearly, annual, or custom.A subscription row's interval column does not match one of those words.
Custom interval requires custom_days of 1 or more.Interval is "custom" but custom_days is blank or less than 1.
Status must be "active" or "cancelled", or left blank for active.A subscription row's status column holds anything else.
A cancelled subscription needs the date it was cancelled in the cancelled_date column, in YYYY-MM-DD format.The status is "cancelled" but cancelled_date is blank or not a real date in that format.
The cancelled_date cannot be before the start date.The cancelled_date is earlier than the row's date column.
The cancelled_date cannot be later than today in UTC (...).The cancelled_date is in the future. The message shows today's date in UTC.
Only a subscription whose status is "cancelled" can have a cancelled_date.A subscription row that is not cancelled has a cancelled_date filled in.
Could not import this row.The row passed every check but failed to save.

Up to 20 row errors are listed by row number; beyond that, a final line states how many more there were.