Historical Transaction Uploads
Overview
Kard supports bulk file-based ingestion of historical transactions for issuers onboarding new users or backfilling historical data after enrollment. Instead of submitting historical transactions one user at a time via the per-user upload API, you can upload a single file containing historical transactions for many users at once. Kard processes the file asynchronously and notifies you via webhook when processing is complete.
This guide covers how to request a presigned upload URL, prepare and upload your transaction file, and interpret the webhook notification you’ll receive once processing is complete.
Migrating from the per-user upload API. The multi-part Historical Transactions Upload API (Create Upload → Add Upload Part → Update Upload) is deprecated in favor of the bulk flow described in this guide. Existing integrations will continue to work until end of year 2027, but new integrations should use the bulk flow. The bulk flow supports millions of transactions per upload (vs. 500 per request) and a single file across many users (vs. one upload per user).
Key Concepts
Transaction Types
Each line in the file describes a single historical transaction. Two transaction types are supported — pick the one that matches your data source.
File Format
Transaction files use JSONL format — one JSON object per line, with no wrapping array or commas between lines. Files can be plain text or gzip-compressed; Kard auto-detects the format. A single upload supports files up to 5 GB.
Processing Model
The flow is asynchronous and mirrors Kard’s daily Bulk Transaction Upload API:
- Request an upload URL. Call the file uploads endpoint to receive a presigned S3 URL.
- Upload the file. Send your JSONL file directly to S3 using the presigned URL.
- Kard processes the file. Each line is validated and accepted records are forwarded to historical transaction storage.
- Receive a completion webhook. Once processing finishes, Kard sends a
fileProcessingResultnotification with a download link to a results file containing any per-line errors.
Implementation
Step 1: Request a Presigned Upload URL
Call the file uploads endpoint to receive one presigned S3 URL per file you intend to upload. You may request up to 10 URLs in a single call — one per file.
Request body:
Response (201 OK):
Presigned URLs expire after 15 minutes. If your URL expires before you complete the upload, simply request a new one.
Step 2: Prepare Your Transaction File
Each line in the file is a single JSON object representing one transaction. Choose the transaction type that matches your data source.
type: historicalTransaction
Use this type if you have card-linked transaction data with merchant and card metadata.
Example line (formatted across multiple lines for readability — in your .jsonl file each transaction must be on a single line):
Field reference:
merchant object:
type: coreHistoricalTransaction
Use this type if you operate on a core banking system that lacks card or merchant detail. This type mirrors the relationship between coreTransaction and transaction in the daily ingestion flow.
Example line:
Field reference:
Step 3: Upload the File
Once you have a presigned URL, upload your file using a standard HTTP PUT. The file is sent directly to Kard’s secure storage.
Plain text:
Gzip-compressed:
A 201 response means the upload succeeded and Kard has begun processing the file.
The presigned URL accepts uploads up to 5 GB. For files with millions of rows, gzip compression typically reduces size by ~75%.
Step 4: Receive the Completion Webhook
Once Kard finishes processing your file, a single fileProcessingResult notification is sent to your configured webhook URL. The notification contains a presigned download URL pointing to a results file in Kard’s S3 bucket.
To configure webhook subscriptions, see the Create Subscription API.
Example payload:
The fileProcessingResult notification is only sent once ingestion has fully completed. If you do not receive it, treat that as an indication the file did not complete processing successfully.
Step 5: Download and Interpret the Results File
Use the downloadUrl from the notification to fetch the results file via a standard HTTP GET. The presigned URL expires after a set period — download promptly.
The results file lists any per-line errors encountered during ingestion. A successful ingestion with no errors will return a single success message with an empty errors array.
Example results file:
If errors is empty, the file processed cleanly. Otherwise, use errors[].detail and errors[].id to correlate failures back to specific lines in your original file, then remediate and re-submit any failed transactions in a new file.
Idempotency. If a transaction is submitted more than once (e.g. across overlapping files or a retry), Kard treats the duplicate as a successful no-op. You do not need to track which transactions have already been sent.
Best Practices
- Use gzip compression for large files. For files with millions of rows, compression significantly reduces upload time and bandwidth.
- Use consistent user identifiers. The
userIdon each line must match the user identifier you use elsewhere in your Kard integration so transactions are attributed correctly. - Validate locally before uploading. Ensure each line is valid JSON and conforms to the schema for the type you’re sending. Invalid lines are reported in the results file but the rest of the file still processes.
- Use the presigned URL exactly as returned. Do not modify the URL, query parameters, or method.
- Request a new URL if yours expires. Presigned URLs are valid for 15 minutes. If your upload takes longer to prepare, simply request another one.