Skip to content
Last updated

File upload processing-result webhook

Version 1.2 uses the signed FileUploadProcessingResult event for native and Plaid automated files. It replaces the schema-only event in this public contract. Production sends a terminal file result after validation failure or ingestion completion/failure. Successful sandbox validation reports validation_only with validationStatus=passed; failed validation reports failed with validationStatus=failed. A passing validation result in production is not the terminal ingestion result.

Envelope

{
  "webhookId": "evt_77777777-7777-4777-8777-777777777777",
  "type": "FileUploadProcessingResult",
  "data": {
    "fileId": "fu_77777777-7777-4777-8777-777777777777",
    "filename": "batch-2026-10-01-001.csv",
    "content": "percents-txn-stream",
    "receivedAt": "2026-10-01T12:01:00.000Z",
    "validatedAt": "2026-10-01T12:02:00.000Z",
    "processingStartedAt": "2026-10-01T12:02:00.000Z",
    "processingFinishedAt": "2026-10-01T12:03:00.000Z",
    "validationStatus": "passed",
    "processingStatus": "completed",
    "counts": {"detectedRows": 100, "ingestedRows": 100, "duplicateRows": 0, "rejectedRows": 0},
    "errorMetadata": null,
    "errorUuid": null
  }
}

The result fields have the same meaning as the corresponding file-status fields. The webhook omits reservation-only status fields such as createdAt, uploadExpiresAt, fileType, uploadStatus, and processingMode. Counts may be null when unavailable; timestamp fields may be null when a stage has not occurred. Use fileId to reconcile the reservation.

Validation rejects the whole native or Plaid file before ingestion if its contract is invalid. Plaid reference errors can include missingAccountIds and unknownPercentsMerchantIds with a required message. ingestedRows counts persisted transaction facts, including transactions rejected by reward eligibility rules. duplicateRows counts skipped known duplicates. rejectedRows counts file-validation or technical ingestion failures, excluding reward/business rejection. These counts describe file handling, not transaction approvals. processingStartedAt records actual ingestion start and remains null when ingestion never begins. processingFinishedAt records terminal file handling, including validation failure or successful sandbox validation; it does not imply ingestion occurred. Rewards, invoices, and final individual transaction determinations are outside this contract.

Receiver behavior

  1. Retain the raw request body and verify X-Percents-Signature.
  2. Deduplicate deliveries by webhookId.
  3. Durably record the result and return 2xx quickly.
  4. For failed files, inspect errorMetadata and errorUuid, correct the source, and use a new filename for resubmission.

Percents sends file results to your entity's configured webhook destination using its signing key. If no destination is configured, file processing still completes and the result remains available for delivery after a destination is configured. Percents bounds each delivery attempt to ten seconds and retries unsuccessful delivery with increasing delays. A delivery failure does not change the file-processing result. Receivers must be idempotent because the same webhookId can be delivered more than once. Use the status endpoint to reconcile a delayed or missing webhook.