---
title: "Submit a batch operation for one or more customers"
method: POST
path: "/api/v1/batch"
tags: ["Batch"]
---

# Submit a batch operation for one or more customers

`POST /api/v1/batch`

## Request

- Base URL: `https://slopeai.slopepay.com`
- URL: `https://slopeai.slopepay.com/api/v1/batch`
- Auth: HTTP bearer

Ingest and process customer data asynchronously. The operation determines whether the request only stores data (INGEST), runs transaction enrichment (ENRICH), or runs full evaluation (EVALUATE) for the requested `product`: attributes (features, monthly financials, recurring cash flows), Slope Score, or both. Internally, evaluation requests are stored in S3 and Python is invoked with an S3 reference.

## Headers

- `Idempotency-Key` string: Optional idempotency key for safely retrying batch submissions. Reusing the same key with an identical request body replays the original response; reusing it with a different body returns IDEMPOTENCY_MISMATCH (400). Keys expire after a TTL.

## Request body

- union: The batch's `operation` is the highest processing stage to run for each customer. `include_score` is no longer supported; use `product`.
  - IngestOrEnrichBatchRequest
    - `operation` 'INGEST' | 'ENRICH', required: INGEST stores data only; ENRICH also runs transaction enrichment. `product` is rejected for these operations.
    - `customers` BatchCustomer[], required: Array of customers to process (1-100). The request may contain at most 50000 transactions across all customers; larger requests are rejected with REQUEST_TOO_LARGE (400).
      - `customer` Customer, required
        - `customer_id` string, required: Unique customer identifier in the client's system
        - `type` 'business' | 'individual' | 'nonprofit': Type of customer
        - `first_name` string
        - `last_name` string
        - `business_name` string
      - `accounts` Account[]
        - `account_id` string, required
        - `type` 'depository' | 'liability': Type of account. When omitted, new accounts default to depository and existing accounts keep their stored type.
        - `number_mask` string, nullable
        - `name` string, nullable
      - `balances` AccountBalance[]
        - `account_id` string, required: Identifier for the account this balance belongs to
        - `date` string, date-time, required: Timestamp at which this balance was observed from the provider
        - `current` integer, nullable: Current balance in cents as of the observed timestamp
        - `available` integer, nullable: Available balance in cents as of the observed timestamp
        - `currency` string
      - `transactions` Transaction[]: Up to 50000 transactions per customer. Transactions are upserted by transaction_id; when a transaction_id repeats within one customer, the last occurrence wins.
        - `transaction_id` string, required
        - `account_id` string, required
        - `description` string, required
        - `amount` integer, required: Signed amount in cents. Positive = outflow (money leaving the account); negative = inflow (money entering the account).
        - `date` string, date-time, required: Posting date for the transaction
        - `authorized_date` string, date-time, nullable
        - `currency` string
  - EvaluateBatchRequest
    - `operation` 'EVALUATE', required: Enriches transactions, then evaluates each customer
    - `product` 'ATTRIBUTES' | 'SCORE' | 'ATTRIBUTES_AND_SCORE', required: What an EVALUATE returns: cash flow attributes (features, monthly financials, and recurring cash flows), the Slope Score with its reasons, or both
    - `customers` BatchCustomer[], required: Array of customers to process (1-100). The request may contain at most 50000 transactions across all customers; larger requests are rejected with REQUEST_TOO_LARGE (400).
      - `customer` Customer, required
        - `customer_id` string, required: Unique customer identifier in the client's system
        - `type` 'business' | 'individual' | 'nonprofit': Type of customer
        - `first_name` string
        - `last_name` string
        - `business_name` string
      - `accounts` Account[]
        - `account_id` string, required
        - `type` 'depository' | 'liability': Type of account. When omitted, new accounts default to depository and existing accounts keep their stored type.
        - `number_mask` string, nullable
        - `name` string, nullable
      - `balances` AccountBalance[]
        - `account_id` string, required: Identifier for the account this balance belongs to
        - `date` string, date-time, required: Timestamp at which this balance was observed from the provider
        - `current` integer, nullable: Current balance in cents as of the observed timestamp
        - `available` integer, nullable: Available balance in cents as of the observed timestamp
        - `currency` string
      - `transactions` Transaction[]: Up to 50000 transactions per customer. Transactions are upserted by transaction_id; when a transaction_id repeats within one customer, the last occurrence wins.
        - `transaction_id` string, required
        - `account_id` string, required
        - `description` string, required
        - `amount` integer, required: Signed amount in cents. Positive = outflow (money leaving the account); negative = inflow (money entering the account).
        - `date` string, date-time, required: Posting date for the transaction
        - `authorized_date` string, date-time, nullable
        - `currency` string

## Response `202`

Batch accepted for asynchronous processing

- BatchSubmissionResponse
  - `job_id` string, required
  - `operation` 'INGEST' | 'ENRICH' | 'EVALUATE', required: The processing operation to run
  - `product` 'ATTRIBUTES' | 'SCORE' | 'ATTRIBUTES_AND_SCORE' | 'null', nullable, required: The requested product; null for INGEST and ENRICH
  - `items` JobItemStatus[], required: Per-customer acceptance or immediate rejection status
    - `index` integer, required: Zero-based index of the entry in the original batch request
    - `customer_id` string, required
    - `status` 'pending' | 'running' | 'succeeded' | 'failed' | 'rejected', required: Per-customer item status
    - `use_case` 'ONBOARDING' | 'MONITORING' | 'null', nullable, required: The use case this customer's evaluation was metered under, set once the entry succeeds. Null for INGEST and ENRICH jobs and for entries that have not succeeded.
    - `errors` ErrorDetail[], nullable: Errors captured for this entry, if any
      - `code` string, required: Per-item error code. Known values: SCHEMA_VALIDATION, MISSING_ACCOUNT, MISSING_BALANCE_FOR_ACCOUNT, MISSING_TRANSACTION_FOR_ACCOUNT, BALANCE_OUTSIDE_TRANSACTION_SPAN, UNKNOWN_ACCOUNT, INGEST_ERROR.
      - `type` 'SCHEMA_VALIDATION' | 'BUSINESS_RULE' | 'SYSTEM', required: Error type classification
      - `message` string, required
      - `fields` string[]: Optional list of related fields for this error
      - `details` object, nullable: Optional structured details for this error

## Other responses

- `400`: Invalid batch request. Causes include malformed JSON (INVALID_JSON), request schema validation failures (VALIDATION_FAILED), per-customer validation where all customers are rejected (SCHEMA_VALIDATION), more transactions across all customers than the per-request maximum (REQUEST_TOO_LARGE), and reusing an Idempotency-Key with a different body (IDEMPOTENCY_MISMATCH).
- `401`: Missing or invalid API key
- `413`: Request JSON body exceeds the maximum byte size (REQUEST_TOO_LARGE); split it into smaller requests
- `500`: Unexpected server error

---

[API](https://skmtc.dev/slopepay/apis/slopeai-api.md) - [All operations](https://skmtc.dev/slopepay/apis/slopeai-api/llms.txt) - [OpenAPI document](https://skmtc.dev/slopepay/apis/slopeai-api/revisions/c3a6761e9639?raw)
