Payment Imports
Create many payments in a batch from a CSV or Excel file, check every row, then turn the valid rows into payments.
A payment import turns a spreadsheet into payments in one batch. You upload the file, Payment Labs validates every row and tells you what each row will do, and you then decide whether to create the payments. Use an import when the payouts already live in a spreadsheet; when your system creates payments one by one, call Create Payment instead.
Before you start
- You have a batch. The batch supplies the default payment category and tax jurisdiction for rows that leave them empty.
- Imports need the Write permission; reading them needs any payout role.
- The payments an import creates are
DRAFT. Finishing an import does not submit them.
The file format
- CSV (
text/csv) or Excel.xlsx(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet). Only the first sheet of an Excel file is read. - One header row, then one row per payment. Rows above the header are ignored: the header is the first row that contains both an email column and an amount column. You can keep instructions or comments above it.
- Header names must be spelled exactly as listed below (letter case included). Spaces around them are ignored. Columns with other names are ignored.
| Column | Other accepted names | Required | Content |
|---|---|---|---|
Email Address | payeeEmail | Yes | The payee's email. |
Amount | Prize Payout, amount | Yes | The amount in the ledger account's currency, digits and a decimal point only: 1000.00, not 1,000.00 or $1000. |
Payee Reference ID | payeeReferenceId | No | Your ID for the payee. See Payee Reference IDs. |
Payment Reference ID | Reference, Reference ID, referenceId | No | Your own label for the payment. |
Account | account | When you have more than one ledger account | The ledger account's alias or id, in any letter case. With one ledger account, leave it empty. |
Tax Jurisdiction | taxJurisdiction | When your account has more than one jurisdiction and the batch has none | us, gb, de, fi, pl, se, sa, my or none, and enabled on your account. Defaults to the batch's. |
Payment Category | paymentCategory | No | One of the payment categories. Defaults to the batch's. |
Payee Message | Payee Memo | No | A note the payee sees. |
Payor Memo | payorMemo | No | A note only you see. |
tag_<key> | — | No | A tag on the payment, for example a column tag_Department with the value marketing;internal. Separate several values with ;. Only accepted when tags are enabled on your account. |
If you connected QuickBooks or Xero, the import also accepts their classification columns, which are passed to that integration:
| Column | Other accepted names | Content |
|---|---|---|
QuickBooks Category | Category | QuickBooks category. |
QuickBooks Class | Class | QuickBooks class. |
QuickBooks Location | QuickBooks Department, Location, Department | QuickBooks location or department. |
Xero Account | — | Xero account. |
tracking_<category> | — | One column per Xero tracking category, for example tracking_Region. |
A minimal CSV:
Email Address,Amount,Payee Reference ID,Payment Reference ID,Payee Message
[email protected],250.00,user-1001,invoice-4471,October royalties
[email protected],1200.50,user-1002,invoice-4472,October royaltiesThe Payment Labs dashboard offers the same template for download from the batch import screen.
Step 1: Create the import
curl -X POST https://api-sandbox.paymentlabs.io/batches/B-01JDA1B2C3D4E5F6G7H8J9K0M1/imports \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "fileName": "october-royalties.csv", "fileMimeType": "text/csv" }'Create Import returns 201:
{
"importId": "I-01JDA5E6F7G8H9J0K1M2N3P4Q5",
"fileUploadUrl": "https://..."
}The import is created. Both fields are required, and fileMimeType must be one of the two types above.
Step 2: Upload the file
Send the file with an HTTP PUT to fileUploadUrl. Do not add your Authorization header: the URL carries its own signature.
curl -X PUT "$FILE_UPLOAD_URL" \
-H "Content-Type: text/csv" \
--data-binary @october-royalties.csvThe upload URL is valid for one hour. An import whose file is never uploaded is removed after a few hours.
Step 3: Wait for validation
Payment Labs starts reading the file as soon as it arrives. Poll Get Import every few seconds until status is no longer processing:
| Status | Meaning | Next |
|---|---|---|
created | Waiting for the file. | Upload it. |
processing | Reading and validating rows. | Keep polling. |
ready | Every row is valid. | Review, then finish. |
processed_with_errors | At least one row is invalid. | Review the errors. Fix the file in a new import, or finish with importValid. |
processing_failed | The file could not be read: no header row with the required columns, no data rows, or an unreadable file. | Delete it and start a new import with a corrected file. |
finishing | Creating the payments. | Keep polling. |
finished | Payments are created. | Submit them. |
entries on the import counts rows: total, validated (rows checked so far, valid or not), failed, and processed once finishing has created payments.
To list every import of a batch, call Get Batch Imports.
Step 4: Review the rows
Get Import Rows returns the rows, 100 per page by default. When the response has nextPage, pass it as exclusiveStartId to read the next page; it is absent on the last page. totalCount is the number of rows in the file.
{
"totalCount": 2,
"currentCount": 2,
"items": [
{
"importId": "I-01JDA5E6F7G8H9J0K1M2N3P4Q5",
"batchId": "B-01JDA1B2C3D4E5F6G7H8J9K0M1",
"paymentId": "P-01JDA6F7G8H9J0K1M2N3P4Q5R6",
"payeeEmail": "[email protected]",
"payeeReferenceId": "user-1001",
"amount": { "value": 250, "currency": "USD", "formattedValue": "$250.00", "digits": 2, "wholeValue": 25000 },
"valid": true,
"userAction": "NO_CHANGE"
},
{
"importId": "I-01JDA5E6F7G8H9J0K1M2N3P4Q5",
"batchId": "B-01JDA1B2C3D4E5F6G7H8J9K0M1",
"payeeEmail": "kenji.mori@example",
"valid": false,
"error": { "payeeEmail": [{ "code": "INVALID_EMAIL", "message": "..." }] }
}
]
}validtells you whether the row will become a payment.errormaps each field to the problems found in it.userActiontells you what the row does to the payee:NO_CHANGE,NEW_PAYEE,EMAIL_CHANGEDorREFERENCE_CHANGED. Check everyEMAIL_CHANGEDandREFERENCE_CHANGEDrow before you finish; see Payee Reference IDs.paymentIdis the ID the payment will have once it is created.expenseAccountName,classNameandlocationNamerepeat the QuickBooks category, class and location you wrote in the row, as typed. A name your QuickBooks company does not have is reported under the same key inerror, but the row staysvalid: the payment is created and you can classify it later.
Common row errors: a missing or invalid email or amount, an Account that is not one of your ledger accounts (or is missing when you have several), a jurisdiction or category that is unknown or not enabled, a payee email and reference ID that belong to different payees, and the same reference ID used with two different emails in the file (INCONSISTENT_REFERENCE_ID).
Step 5: Finish the import
Finish Import creates the payments. It returns 202 and the import moves to finishing, then finished.
{ "errorHandling": "importValid" }errorHandling | Effect |
|---|---|
allOrNone | Create payments only if every row is valid. On an import with errors the call returns 400 and nothing is created. |
importValid | Create payments for the valid rows and skip the invalid ones. |
The new payments are DRAFT. Submit them like any other payment, for example all at once with Submit Batch. See Creating and Submitting Payments.
Delete an import
Delete Import discards an import that has not been finished: one in created, ready, processed_with_errors or processing_failed. It returns 204. It creates and deletes no payments.
Errors and edge cases
| Error | Operation | Meaning | What to do |
|---|---|---|---|
400 VALIDATION_ERROR | Create | fileName or fileMimeType is missing or invalid. | Fix the body. |
404 NOT_FOUND | All | The batch or import does not exist or is not yours. | Check the IDs. |
400 with message: "Import has failed entries" | Finish | You sent allOrNone and some rows are invalid. | Finish with importValid, or fix the file in a new import. |
423 | Finish | The import is not ready or processed_with_errors. | Wait for validation, or check that it is not already finished. |
423 NOT_EDITABLE | Delete | The import is processing, finishing or finished. | Nothing to delete. |
Next steps
Updated 1 day ago
What’s Next
Next: Payment Requests.
