---
title: "Upload events (Batch)"
method: POST
path: "/batch"
tags: ["Ingestion"]
---

# Upload events (Batch)

`POST /batch`

## Request

- Base URL: `https://api2.amplitude.com`
- URL: `https://api2.amplitude.com/batch`
- Auth: none required

Upload large volumes of event data at once. Same payload shape as HTTP V2 with higher throughput limits and looser throttling. Use this for backfills and server-to-server pipelines.

**Retrying safely.** As with HTTP V2, idempotency is keyed on each event’s `insert_id` rather than an `Idempotency-Key` header. Backfills are the case where this matters most: a retried batch without stable `insert_id` values silently duplicates every event it contains.

## Request body

- UploadRequestBody
  - `api_key` string, required: Amplitude project API key.
  - `events` Event[], required: Events to upload.
    - `event_type` string, required: Unique identifier for the event. `$identify` and `$groupidentify` are reserved for identification.
    - `user_id` string: ID for the user. Minimum 5 characters unless overridden with `min_id_length`.
    - `device_id` string: Device-specific identifier.
    - `time` integer: Event timestamp in milliseconds since epoch. Defaults to upload time.
    - `event_properties` object: Data sent along with the event. Max depth 40.
    - `user_properties` object: Data tied to the user. Supports `$set`, `$setOnce`, `$add`, `$append`, and `$unset` when `event_type` is `$identify`.
    - `groups` object: Event-level groups. Requires the Accounts add-on. Up to 5 group types and 10 group values per event.
    - `group_properties` object: Properties tied to the groups in `groups`. Applies when `event_type` is `$groupidentify`.
    - `insert_id` string: Idempotency key for this event. Amplitude discards an event whose `insert_id` matches one already received for the same `device_id` within the last 7 days. Generate it before the first send — deterministically from the event, or as a UUID stored with it — and reuse the same value on every retry. Generating a fresh one per attempt defeats deduplication entirely.
    - `session_id` integer: Session start time in milliseconds since epoch. `-1` means no session.
    - `event_id` integer: Incrementing counter that distinguishes events with the same user and timestamp.
    - `app_version` string
    - `platform` string
    - `os_name` string
    - `os_version` string
    - `device_brand` string
    - `device_manufacturer` string
    - `device_model` string
    - `carrier` string
    - `country` string
    - `region` string
    - `city` string
    - `dma` string
    - `language` string
    - `location_lat` number
    - `location_lng` number
    - `ip` string: IP address of the user. Use `$remote` to use the request IP.
    - `user_agent` string: Unparsed user agent string, which Amplitude parses into user properties.
    - `price` number
    - `quantity` integer
    - `revenue` number: Revenue amount. When price and quantity are both sent, revenue is price × quantity.
    - `productId` string
    - `revenueType` string
    - `currency` string: Three-character uppercase ISO 4217 code.
    - `idfa` string
    - `idfv` string
    - `adid` string
    - `android_id` string
    - `android_app_set_id` string
    - `plan` object: Tracking plan metadata.
      - `branch` string
      - `source` string
      - `version` string
  - `options` object
    - `min_id_length` integer: Overrides the default minimum length of 5 for `user_id` and `device_id`.

## Response `200`

Events accepted.

- UploadSuccess
  - `code` 200
  - `events_ingested` integer: Number of events ingested from the request.
  - `payload_size_bytes` integer: Size of the upload payload in bytes.
  - `server_upload_time` integer: Milliseconds since epoch when Amplitude accepted the request.

## Other responses

- `400`: Invalid upload request: malformed JSON, missing required fields, invalid field values, or silenced devices.
- `413`: Payload exceeds 1 MB. Split the events array across multiple requests.
- `429`: Too many requests for a user or device. Pause sending for that user or device for 30 seconds, then retry until the 429 clears.
- `500`: Server error. Retry the request.

## Changes

- **2026-10-14** `e475ad97669a`: 4 breaking, 4 info
  - the response's body type changed from `object` to `object, string` for status `400`
  - the response's body type changed from `object` to `object, string` for status `413`
  - the response's body type changed from `object` to `object, string` for status `429`
  - the response's body type changed from `object` to `object, string` for status `500`
  - …4 more

[Operation history](https://skmtc.dev/amplitude/apis/amplitude-public-apis/changes/batch/post.md)

---

[API](https://skmtc.dev/amplitude/apis/amplitude-public-apis.md) - [All operations](https://skmtc.dev/amplitude/apis/amplitude-public-apis/llms.txt) - [OpenAPI document](https://skmtc.dev/amplitude/apis/amplitude-public-apis/revisions/e475ad97669a?raw)
