Skip to main content
This guide covers the data side of an SFTP integration — what to send, where to put it, and how it should be shaped. For SSH keys, connection setup, and portal workflows, see Connect via SFTP.

The four required objects

Every Daylit SFTP integration must send the four required objects below. They are the minimum needed for open AR, collections workflows, and customer-level reporting. Payment is optional — send it for per-payment-event tracking (see Payment).
ObjectWhat it isExample filenameRequired
CustomerCompanies or individuals you billcustomers_*.csv
Customer ContactAP, billing, and primary contactscontacts_*.csv
InvoiceEvery invoice with embedded payment info (paid amount, paid-on date, balance, due date)invoices_*.csv
Credit NoteRefunds, returns, and applied or unapplied creditscredit_notes_*.csv
PaymentIndividual payment events — one row per invoice allocationpayments_*.csvOptional
Daylit accepts additional objects beyond these four without breaking your integration.

File format

SettingValue
FormatCSV
EncodingUTF-8 (no BOM)
Delimiter (CSV)Comma ,
Quote characterDouble quote ", escape by doubling: "" (RFC 4180)
Line endings\n (LF) or \r\n (CRLF)
Header rowRequired on every file
DatesYYYY-MM-DD (default). Other patterns (MM-DD-YYYY, MM/DD/YYYY, and more) are selectable per field in the mapping UI.
DatetimesISO 8601 UTC — YYYY-MM-DDTHH:MM:SSZ (default). MySQL TIMESTAMP, IBM SQL, and other patterns are selectable per field; timezone-naive values are assumed UTC.
DecimalsDot separator — 1234.56. Currency symbols and thousands separators are stripped automatically; accounting-style negatives ((1234.56)) become -1234.56.
Booleanstrue/false, yes/no, or 1/0
NullsEmpty string

Where to put files (SFTP paths)

After provisioning, your SFTP user sees top-level directories for each upload phase. Place files in the matching object subfolder within each phase.

Upload paths

PathPurpose
/test/Connectivity check — no business validation
/sample/Small file (≤ 100 rows) to validate your mapping
/init/Full snapshot of every record in an object
/delta/Incremental updates since your last successful upload

Per-object directory structure

/test/customer/customers_test_2026-06-04.csv
/test/customer_contact/contacts_test_2026-06-04.csv
/test/invoice/invoices_test_2026-06-04.csv
/test/credit_note/credit_notes_test_2026-06-04.csv
/test/payment/payments_test_2026-06-04.csv

/sample/customer/customers_sample_2026-06-04.csv
/sample/customer_contact/contacts_sample_2026-06-04.csv
/sample/invoice/invoices_sample_2026-06-04.csv
/sample/credit_note/credit_notes_sample_2026-06-04.csv
/sample/payment/payments_sample_2026-06-04.csv

/init/customer/customers_init_2026-06-04.csv
/init/customer_contact/contacts_init_2026-06-04.csv
/init/invoice/invoices_init_2026-06-04.csv
/init/credit_note/credit_notes_init_2026-06-04.csv
/init/payment/payments_init_2026-06-04.csv

/delta/customer/customers_delta_2026-06-04T140000Z.csv
/delta/customer_contact/contacts_delta_2026-06-04T140000Z.csv
/delta/invoice/invoices_delta_2026-06-04T140000Z.csv
/delta/credit_note/credit_notes_delta_2026-06-04T140000Z.csv
/delta/payment/payments_delta_2026-06-04T140000Z.csv
Rules:
  • If a daily delta has nothing to send for an object, skip that object. Daylit won’t penalize an empty interval. Daylit warns if a normally active object goes silent for more than 1.5× its usual cadence.
  • Send one file per object per push. For large inits, use a single .csv.gz rather than splitting into parts.

Upload order for init

Push parents before children so foreign keys resolve immediately:
  1. customer first
  2. customer_contact (references Customer)
  3. invoice (references Customer)
  4. credit_note (references Customer)
  5. payment (optional; references Invoice)
Daylit can accept files in any order and holds ingestion until referenced parents exist, but dependency order surfaces FK errors sooner.

Canonical schema per object

Every object has a canonical schema — the field names and types Daylit expects after your mapping is applied. You don’t rename columns in your source system; you map them in the portal on Settings -> SFTP connection. Schemas are versioned. Schemas below are v1.

Conventions used in every object

FieldPurpose
remote_idThe record’s identifier in your source system. Required on every row. Daylit upserts on this value.
remote_updated_atISO 8601 UTC timestamp of the last modification in your source system. Must increase monotonically per remote_id.
*_remote_idForeign key to another object’s remote_id (for example, customer_remote_id on an invoice).
statusNormalized lifecycle state. Allowed values are listed per object.

Customer

One row per customer. Daylit upserts on remote_id — a repeated remote_id updates the existing customer, a new one inserts. Upload to /init/customer/ and /delta/customer/. Customer is the parent record, so make sure to upload Customers before any other object.
FieldTypeRequiredNotes
remote_idstringUnique per customer in your source system
customer_company_namestringLegal/billing entity name
remote_updated_atdatetimeSource-system last-modified timestamp. Drives incremental sync.
address_line1stringoptional
address_line2stringoptional
address_citystringoptional
address_statestringoptional2-letter US state or ISO 3166-2 subdivision
address_zipcodestringoptional
address_countrystringoptionalISO 3166-1 alpha-2 (US, GB, IN). Can be set to a static value if all customers share one country.
default_payment_termsstringoptionalNet-N days, e.g. 30 for Net 30
credit_limitdecimaloptional

Customer Contact

One row per contact; a customer can have zero, one, or many. Daylit upserts on remote_id. Upload to /init/customer_contact/ and /delta/customer_contact/, after the customers they reference via customer_remote_id.
FieldTypeRequiredNotes
remote_idstringUnique per contact
customer_remote_idstringFK to Customer.remote_id
emailstringPrimary email for this contact
first_namestringoptional
last_namestringoptional
phonestringoptionalE.164 preferred
titlestringoptionalJob title, e.g. Accounts Payable Manager
departmentstringoptionale.g. Finance, Accounting
is_primarybooleanoptionaltrue if this is the customer’s main contact. Defaults to false.
If your source stores contacts as columns on the customer record (billing_email, billing_contact_name), you can emit a synthetic Contact row per customer using customer_remote_id + "_primary" as the contact’s remote_id, or put the email on the Customer record and skip Contacts. Contact Daylit if you’re unsure which fits your data shape.

Invoice

One row per invoice. Payment summary fields (paid_amount, paid_on_date, balance) are embedded on the invoice row, not sent as a separate object. Daylit upserts on remote_id. Upload to /init/invoice/ and /delta/invoice/, after the customers they reference via customer_remote_id.
FieldTypeRequiredNotes
remote_idstringUnique per invoice
customer_remote_idstringFK to Customer.remote_id
remote_updated_atdatetime (ISO 8601 UTC)
numberstringHuman-readable invoice number
issue_datedateDate the invoice was issued
due_datedateDate the invoice is due
total_amountdecimalGrand total, including taxes and fees
paid_amountdecimalCumulative amount paid. 0 if unpaid
balancedecimalSend explicitly — don’t make Daylit calculate it
paid_on_datedateoptionalDate the invoice was fully paid. Empty if not fully paid.
currencystringISO 4217
statusenumSee allowed values below
memostringoptional
Allowed status values:
ValueMeaning
DRAFTNot finalized or sent; excluded from AR totals
SUBMITTEDIssued to the customer; payment still expected
OPENOutstanding, amount still due
PARTIALLY_PAIDSome payment received, balance > 0
PAIDFully paid, balance = 0
VOIDCancelled or invalidated; excluded from AR totals
If your source system uses different status text (for example Fully Paid or Not Sent), map it to a canonical value in the portal mapping UI under the status field. Matching is case-insensitive.

Credit Note

One row per credit note — refunds, returns, and credit memos issued to customers. Daylit upserts on remote_id. Upload to /init/credit_note/ and /delta/credit_note/, after the customers they reference via customer_remote_id.
FieldTypeRequiredNotes
remote_idstringUnique per credit note
customer_remote_idstringFK to Customer.remote_id
total_amountdecimalAlways positive — Daylit treats it as a credit
remote_updated_atdatetimeoptionalSource-system last-modified timestamp
numberstringoptionalHuman-readable credit note number
transaction_datedateoptionalDate the credit note was issued
statusenumoptionalSee below. Defaults to SUBMITTED.
remaining_creditdecimaloptionalUnapplied credit still available. 0 if fully applied.
currencystringoptionalISO 4217. Defaults to USD.
exchange_ratedecimaloptionalRate at issuance, if multicurrency
inclusive_of_taxbooleanoptionaltrue if total_amount includes tax. Defaults to false.
memostringoptional
Allowed status values:
ValueMeaning
SUBMITTEDIssued but not yet approved or applied (default)
AUTHORIZEDApproved and available to apply against invoices
PAIDFully applied; no remaining credit
If your source system uses different status text (for example Open or Applied), map it to a canonical value in the portal mapping UI under the status field.

Payment

Daylit ingests payments as one row per invoice allocation. A single payment applied across several invoices is sent as multiple rows that share the same remote_id, each pointing at a different invoice_remote_id with its own applied_amount. Upload to /init/payment/ and /delta/payment/, after the invoices they reference.
FieldTypeRequiredNotes
remote_idstringPayment identifier. Repeated across rows when one payment covers multiple invoices.
invoice_remote_idstringFK to Invoice.remote_id — the invoice this row applies to
total_amountdecimalTotal amount of the payment (the same value on every row for that payment)
applied_amountdecimaloptionalPortion of the payment applied to this invoice row. If omitted, the total amount is assumed to be applied to the linked invoice.
transaction_datedateoptionalDate the payment was received
currencystringoptionalISO 4217. Defaults to USD.
statusstringoptionalSource payment status, e.g. completed, pending
payment_methodstringoptionale.g. ach, card, wire, check
transaction_idstringoptionalBank or processor reference
notesstringoptionalFree-form note
remote_updated_atdatetimeoptionalSource-system last-modified timestamp

Sample CSV files

Example exports showing what each object looks like as a CSV — typical column names from a source system, not the canonical Daylit field names. Use them to understand the shape of each table, as a starting point for your own exports, or to map columns in Settings → SFTP connection. See the canonical schema above for the fields Daylit expects after mapping. For full sample data across all five objects, open the Sample CSV spreadsheet — one tab per object. Use File → Download in Google Sheets to export as CSV.
Customer, contact, invoice, credit note, and payment rows share the same IDs across these files (for example, CUST-900001 and INV-900001). Match that pattern in your exports so foreign keys line up between objects.
customers_sample.csv
ERP_Customer_ID,Customer_Name,Last_Modified,Billing_Address1,Billing_Address2,Billing_City,Billing_State,Billing_Zip,default_payment_terms
CUST-900001,Sterling Enterprises 620,09-07-2024 3:01:47,4507 Cedar Dr,Suite 9035,Chicago,IL,60601,
CUST-900002,Quantum Enterprises 3711,05-24-2026 2:13:14,8280 Hill St,,Portland,OR,97201,NET 60
CUST-900003,Vertex Group 3627,03-21-2025 18:17:51,107 Sunset Blvd,,Austin,TX,78701,
contacts_sample.csv
ERP_Contact_ID,ERP_Customer_ID,First_Name,Last_Name,Email,Phone,Title,Is_Primary
CONT-900001,CUST-900001,Tina,Nguyen,tina.nguyen0@sterlingenterprises620.com,(424) 851-4115,Billing Manager,TRUE
CONT-900002,CUST-900002,Elena,Davis,elena.davis0@quantumenterprises3711.com,(842) 861-1645,AP Manager,TRUE
CONT-900003,CUST-900003,Elena,Chen,elena.chen0@vertexgroup3627.com,(502) 534-7807,Accounts Payable Specialist,TRUE
invoices_sample.csv
ERP_Invoice_Number,Customer_Account_ID,Updated_At,Invoice_Number,Date_Billed,Due_Date,Paid_On,Grand_Total_USD,Paid_Total_USD,Open_Balance_USD,Merge_Status
INV-900001,CUST-900001,10-03-2024 17:05:32,IN-900001,08-23-2024,10-07-2024,11-06-2024,1730.31,1730.31,0,PAID
INV-900002,CUST-900002,01-07-2026 19:46:57,IN-900002,12-19-2025,01-18-2026,03-02-2026,1636.33,1636.33,0,PAID
INV-900003,CUST-900003,06-14-2026 1:41:49,IN-900003,04-13-2026,04-28-2026,05-10-2026,1561.97,1561.97,0,PAID
credit_notes_sample.csv
ERP_Credit_Note_ID,ERP_Customer_ID,Credit_Note_Number,Transaction_Date,Status,Total_Amount,Remaining_Credit,Exchange_Rate,Inclusive_Of_Tax,Memo,Updated_At
CN-900001,CUST-900001,CR-900001,06-27-2025,SUBMITTED,518.29,518.29,1,FALSE,Promotional credit,12-09-2025 0:18:26
CN-900002,CUST-900002,CR-900002,09-19-2025,SUBMITTED,232.16,232.16,1,FALSE,Service credit,10-01-2025 5:43:24
CN-900003,CUST-900003,CR-900003,01-06-2025,AUTHORIZED,371.7,50.41,1,FALSE,Returned goods credit,01-26-2026 2:10:27
payments_sample.csv
ERP_Payment_ID,Payment_Total_USD,Updated_At,Invoice_ID,Applied_Amount,Payment_Date,Payment_Status,Payment_Method,Payment_Reference,Notes
PAY-900001,1730.31,12-26-2025 7:37:20,INV-900001,1730.31,11-06-2024,processing,Wire,REF-PAY-900001,Batch settlement
PAY-900002,1636.33,06-21-2026 22:44:22,INV-900002,1636.33,03-02-2026,processing,Wire Transfer,REF-PAY-900002,Customer payment
PAY-900003,1561.97,05-19-2026 6:53:51,INV-900003,1561.97,05-10-2026,pending,Wire Transfer,REF-PAY-900003,Partial payment

Foreign keys and object relationships

Rules:
  • CustomerContact.customer_remote_id must match an existing Customer.remote_id.
  • Invoice.customer_remote_id must match an existing Customer.remote_id.
  • CreditNote.customer_remote_id must match an existing Customer.remote_id.
  • Payment.invoice_remote_id must match an existing Invoice.remote_id.
  • Foreign keys resolve at the end of each batch. If a child file arrives before its parent, Daylit holds it for up to 24 hours, then quarantines it with an FK-unresolved error.

Validation rules summary

A file passes validation when all of the following hold: Structure
  • Path is /{phase}/{object}/{filename} with recognized phase and object values.
  • Filename matches {object}_{phase}_{date}.
  • File parses cleanly: correct encoding, header row present, no truncated rows.
Per row
  • Every required field is non-empty.
  • Every cell satisfies its declared type.
  • remote_id is non-empty.
Per file
  • remote_id is unique within the file.
  • For init: row count is between 1 and 10× the largest sample ever sent for this object.
  • For delta: remote_updated_at per remote_id is monotonically increasing.
Cross-file (init/delta)
  • Every *_remote_id foreign key resolves to a known parent record.
If validation fails, the file is quarantined with a failure report listing the first 10 failing rows and the reason for each. Fix and re-upload — no penalty.

Worked example: ACME Corporation’s first init

ACME Corporation exports all five objects and uploads in order:
sftp daylit
sftp> put customers_init_2026-06-04.csv      /init/customer/
sftp> put contacts_init_2026-06-04.csv       /init/customer_contact/
sftp> put invoices_init_2026-06-04.csv       /init/invoice/
sftp> put credit_notes_init_2026-06-04.csv   /init/credit_note/
sftp> put payments_init_2026-06-04.csv       /init/payment/
sftp> bye
Within a few minutes the portal shows:
✓ Customer         init    1,842 rows ingested
✓ Customer Contact init    2,114 rows ingested
✓ Invoice          init   18,422 rows ingested
✓ Credit Note      init      211 rows ingested
✓ Payment          init    4,037 rows ingested
From this point, ACME’s cron uploads hourly deltas to /delta/{object}/ and Daylit stays current.

Need help?

  • Portal in-app chat — bottom-right on every page.
  • Email: support@daylit.com. Include your workspace name and the filename you’re asking about.
  • Status page: status.daylit.com for any active incidents.