Bulk import

Issue many certificates from one CSV or XLSX file, with a review stage that creates nothing until you confirm it.

Import is a five-stage workflow, not an upload button. Validation happens before anything is created, so a file with mistakes in it costs you a correction rather than a hundred wrong certificates.

The five stages

  1. Upload. .csv or .xlsx, up to the size and row limits below. The header row is checked first: an unexpected or missing column stops the file before any row is read.
  2. Validation. Every row is checked against the rules in the table below and stored in a staging area with its own result. Nothing is created.
  3. Correction. The review screen shows each row, valid or not, with the reason for every rejection. Fix them in your file and upload again.
  4. Confirmation. Only an explicit confirmation creates certificates. This is also where you choose whether verification is required, which verifier receives them, and whether notification emails are queued.
  5. Result. A summary of what was created and what failed. Confirming twice does not create a second copy: the batch resumes from row state and finishes once.

The columns

The header row must match exactly. Download the template from the import screen, or take it from Sample-Files/certificate-import-template.csv in the package, which is written from the same list the parser uses.

#ColumnRequiredFormatNotes
1course_idYesWhole number, 1 or higherThe course this certificate belongs to. Read it from the course list.
2course_run_idYesWhole number, 1 or higherThe dated occurrence of that course. It must belong to course_id, or the row is rejected.
3certificate_template_idYesWhole number, 1 or higherThe certificate layout to render. It must belong to course_id.
4participant_first_nameYesText, up to 120 charactersPrinted on the certificate exactly as written here.
5participant_last_nameYesText, up to 120 charactersPrinted on the certificate exactly as written here.
6participant_emailYesEmail address, up to 255 charactersEvery certificate is issued to an address, so a notification can always be delivered. A row without one is rejected.
7participant_phoneNoText, up to 80 charactersNever printed on the certificate and never shown publicly.
8participant_organizationNoText, up to 255 charactersThe participant employer, not your own organisation.
9participant_positionNoText, up to 180 charactersJob title, if your certificates show one.
10certificate_numberYesText, up to 120 charactersYour own numbering. It must be unique across the whole system, and it is one of the two values the public can verify with.
11unique_idNoText, up to 120 charactersLeave it empty and the system generates one. It must be unique if you supply it.
12issued_atYesDate as YYYY-MM-DDCannot be in the future.
13expires_atNoDate as YYYY-MM-DDMust not be earlier than issued_at. Leave it empty for a credential that does not expire.

The header row must contain exactly these 13 names. A missing column, an extra column or a different spelling is refused before any row is read, and the screen names the column it could not match.

A valid file

course_id,course_run_id,certificate_template_id,participant_first_name,participant_last_name,participant_email,participant_phone,participant_organization,participant_position,certificate_number,unique_id,issued_at,expires_at
1,1,1,Anna,Larsen,anna.larsen@example.com,+1 555 0101,Example Trading LLC,Analyst,CF-2026-0001,,2026-03-14,2029-03-14
1,1,1,Chen,Wei,chen.wei@example.com,,Example Manufacturing JSC,Compliance Officer,CF-2026-0002,,2026-03-14,

The package includes filled examples in Sample-Files/certificate-import-sample.csv and Sample-Files/certificate-import-sample.xlsx. They contain the same three fictional participants. The three numeric columns are identifiers from your own data, so change them to match a related course, occurrence and template before uploading. Keep XLSX identifiers and ISO dates as text. Use new certificate numbers if you have already imported the examples.

Sample-Files/certificate-import-invalid.csv contains five deliberate row errors for inspecting the correction screen: a missing given name, an invalid email, a nonexistent issue date, a missing certificate number and an expiry before issue. Its headers remain valid. Read Sample-Files/README.md for setup and the expected error for each row. The same directory includes two blank A4 landscape PNG backgrounds and their reuse licence; upload one through the course template editor and place your own fields before issuing.

Where the identifiers come from

The three numeric columns are database identifiers, and the import screen is not where you guess them.

All three lists show their identifiers to Admins and Managers precisely so an import file can be prepared without a database client. An occurrence or template belonging to a different course is rejected row by row, with the reason.

Limits

LimitSet byWhat happens at the limit
File sizeUPLOAD_MAX_MBThe upload is refused before it is read.
Data rowsIMPORT_MAX_ROWSThe file is refused. Split it and upload the parts.
Uncompressed .xlsx sizeIMPORT_XLSX_MAX_UNCOMPRESSED_MBThe file is refused. This is what stops a small archive that expands to gigabytes.

Why a row was rejected

MessageCause
A required field is emptyOne of the required columns has no value in that row. The message names the column.
A value must be a whole numberOne of the three identifier columns holds text, a decimal or a zero.
The occurrence or template does not belong to the courseThe identifiers are valid on their own but do not belong together.
The issue date is invalid or in the futureissued_at is not YYYY-MM-DD, or it is later than today.
The expiry date is before the issue dateexpires_at precedes issued_at.
The certificate number is already in useNumbers and unique IDs are unique across the installation, including against certificates issued months ago.
The email address is not validparticipant_email is malformed. Correct it rather than putting a placeholder in it: the column is required, and a placeholder becomes a notification nobody receives.

Excel and dates. Excel likes to reformat 2026-03-14 into something local. Format the two date columns as text before typing, or save as CSV and check the result in a text editor. This is the single most common reason a prepared file is rejected.

One import belongs to the person who uploaded it. A staged batch can be reviewed and confirmed by its uploader, and by an Admin. Another Manager cannot see or confirm someone else's staged file.