Bulk Ingest API

Upload multiple documents in a single request. The ingest endpoint handles file upload, automatic deal matching, document classification, and queues all files for processing through the analysis pipeline. Use batch status polling or callbacks to track completion.

Include an Idempotency-Key header to safely retry failed uploads without creating duplicate batches.

Bulk Ingest

Uploads one or more files and associates them with a deal. If the deal does not exist, it is created automatically based on the provided matching criteria. Each file is queued for OCR, classification, extraction, and analysis.

NameTypeRequiredDescription
files[]fileRequiredOne or more PDF files to upload (multipart form field)
metadataobjectRequiredJSON object with deal matching, callback config, and file labels
metadata.deal_matchingobjectRequiredCriteria for matching or creating a deal
metadata.deal_matching.business_namestringOptionalBusiness name to match against existing deals
metadata.deal_matching.external_referencestringOptionalExternal reference ID (e.g. CRM record ID)
metadata.deal_matching.einstringOptionalEmployer Identification Number for matching
metadata.callbackobjectOptionalCallback configuration for batch completion notification
metadata.callback.urlstringOptionalHTTPS URL to receive the completion callback
metadata.callback.secretstringOptionalSecret for HMAC-SHA256 signature verification
metadata.labelsobjectOptionalMap of filename to human-readable label
Idempotency-KeystringOptionalUnique key to prevent duplicate batch creation (header)
Request
curl -X POST https://api.banklyze.com/v1/ingest \
  -H "Authorization: Bearer bkz_live_abc123" \
  -H "Idempotency-Key: batch-2025-11-01-acme" \
  -F 'files[]=@acme_oct_2025.pdf' \
  -F 'files[]=@acme_sep_2025.pdf' \
  -F 'files[]=@acme_aug_2025.pdf' \
  -F 'metadata={
    "deal_matching": {
      "business_name": "Acme Trucking LLC",
      "external_reference": "CRM-4821"
    },
    "callback": {
      "url": "https://yourapp.com/webhooks/banklyze",
      "secret": "whsec_abc123def456"
    },
    "labels": {
      "acme_oct_2025.pdf": "October 2025 Statement",
      "acme_sep_2025.pdf": "September 2025 Statement",
      "acme_aug_2025.pdf": "August 2025 Statement"
    }
  };type=application/json'
202 Accepted
{
  "data": {
    "batch_id": "batch_01JDKF9X2M3N4P5Q6R7S8T9U",
    "deal_id": 42,
    "deal_matched": true,
    "match_method": "business_name",
    "files": [
      {
        "filename": "acme_oct_2025.pdf",
        "document_id": 187,
        "label": "October 2025 Statement",
        "status": "queued",
        "size_bytes": 245120
      },
      {
        "filename": "acme_sep_2025.pdf",
        "document_id": 188,
        "label": "September 2025 Statement",
        "status": "queued",
        "size_bytes": 198400
      },
      {
        "filename": "acme_aug_2025.pdf",
        "document_id": 189,
        "label": "August 2025 Statement",
        "status": "queued",
        "size_bytes": 312576
      }
    ],
    "created_at": "2025-11-01T14:30:00Z"
  }
}

Metadata structure

The metadata JSON controls deal matching behavior and optional callback delivery. The deal is matched first by external_reference, then by ein, then by business_name. If no match is found, a new deal is created.

Metadata
{
  "deal_matching": {
    "business_name": "Acme Trucking LLC",
    "external_reference": "CRM-4821",
    "ein": "123456789"
  },
  "callback": {
    "url": "https://yourapp.com/webhooks/banklyze",
    "secret": "whsec_abc123def456"
  },
  "labels": {
    "acme_oct_2025.pdf": "October 2025 Statement",
    "acme_sep_2025.pdf": "September 2025 Statement"
  }
}

Callback payload

When all documents in the batch finish processing, the callback URL receives a POST with the following payload. The request includes an X-Banklyze-Signature header for verification.

Callback POST
{
  "event": "batch.completed",
  "batch_id": "batch_01JDKF9X2M3N4P5Q6R7S8T9U",
  "deal_id": 42,
  "timestamp": "2025-11-01T14:32:45Z",
  "data": {
    "total_documents": 3,
    "completed": 3,
    "failed": 0,
    "recommendation": {
      "decision": "approved",
      "health_score": 74.2,
      "grade": "B",
      "ruleset_id": 1,
      "ruleset_name": "Standard MCA"
    }
  }
}

Batch Status

Returns the current status of a batch, including per-document processing status and the underwriting recommendation summary when all documents have completed.

NameTypeRequiredDescription
batch_idstringRequiredThe batch ID returned from the ingest endpoint
Request
curl https://api.banklyze.com/v1/ingest/batches/batch_01JDKF9X2M3N4P5Q6R7S8T9U \
  -H "Authorization: Bearer bkz_live_abc123"
200 OK
{
  "data": {
    "batch_id": "batch_01JDKF9X2M3N4P5Q6R7S8T9U",
    "deal_id": 42,
    "status": "completed",
    "created_at": "2025-11-01T14:30:00Z",
    "completed_at": "2025-11-01T14:32:45Z",
    "documents": [
      {
        "document_id": 187,
        "filename": "acme_oct_2025.pdf",
        "label": "October 2025 Statement",
        "status": "completed",
        "document_type": "bank_statement",
        "period": "2025-10",
        "transaction_count": 142
      },
      {
        "document_id": 188,
        "filename": "acme_sep_2025.pdf",
        "label": "September 2025 Statement",
        "status": "completed",
        "document_type": "bank_statement",
        "period": "2025-09",
        "transaction_count": 128
      },
      {
        "document_id": 189,
        "filename": "acme_aug_2025.pdf",
        "label": "August 2025 Statement",
        "status": "completed",
        "document_type": "bank_statement",
        "period": "2025-08",
        "transaction_count": 156
      }
    ],
    "recommendation": {
      "decision": "approved",
      "health_score": 74.2,
      "grade": "B",
      "ruleset_id": 1,
      "ruleset_name": "Standard MCA",
      "factor_scores": {
        "revenue_stability": 82,
        "average_daily_balance": 71,
        "deposit_consistency": 76,
        "nsf_frequency": 65,
        "negative_days": 58,
        "high_risk_transactions": 90
      }
    }
  }
}