---
title: "Push MANY files into the primary vault in ONE call. Use this instead of looping sync_push whenever you have more than a couple of changed paths — the cost of sync_push is round trips, not bytes. Per-item semantics are identical to sync_push (Layer 3 base_sha CAS, superseded contract, content_b64 WAF fallback). Partial success is normal and returns HTTP 200: read `results[]` and match entries by `path`, NOT by position. A conflict result always carries `remote_sha` + `conflict_reason` so you can go straight to sync_merge. Request-level failures (duplicate paths in one batch, idempotency key reused with a different payload, >200 items, >4MB) return 4xx and apply NOTHING. Each item MUST carry `content_sha` (SHA1 hex of the decoded body, same algorithm as git_sha) — it powers both the integrity check and the retry-safe `skipped_identical` result. Newly created .md items may carry `dedup_candidates` (same merge/skip/store advisory as sync_push); a batch creating more than 10 new files skips the check entirely and reports `dedup_skipped: \"bulk\"`."
method: POST
path: "/api/mcp/tools/sync_push_batch"
tags: ["sync"]
---

# Push MANY files into the primary vault in ONE call. Use this instead of looping sync_push whenever you have more than a couple of changed paths — the cost of sync_push is round trips, not bytes. Per-item semantics are identical to sync_push (Layer 3 base_sha CAS, superseded contract, content_b64 WAF fallback). Partial success is normal and returns HTTP 200: read \`results\[\]\` and match entries by \`path\`, NOT by position. A conflict result always carries \`remote_sha\` + \`conflict_reason\` so you can go straight to sync_merge. Request-level failures (duplicate paths in one batch, idempotency key reused with a different payload, >200 items, >4MB) return 4xx and apply NOTHING. Each item MUST carry \`content_sha\` (SHA1 hex of the decoded body, same algorithm as git_sha) — it powers both the integrity check and the retry-safe \`skipped_identical\` result. Newly created .md items may carry \`dedup_candidates\` (same merge/skip/store advisory as sync_push); a batch creating more than 10 new files skips the check entirely and reports \`dedup_skipped: "bulk"\`.

`POST /api/mcp/tools/sync_push_batch`

## Request

- Base URL: `https://api.ainote.dev`
- URL: `https://api.ainote.dev/api/mcp/tools/sync_push_batch`
- Auth: API key in header `Authorization`

Push MANY files into the primary vault in ONE call. Use this instead of looping sync_push whenever you have more than a couple of changed paths — the cost of sync_push is round trips, not bytes. Per-item semantics are identical to sync_push (Layer 3 base_sha CAS, superseded contract, content_b64 WAF fallback). Partial success is normal and returns HTTP 200: read `results[]` and match entries by `path`, NOT by position. A conflict result always carries `remote_sha` + `conflict_reason` so you can go straight to sync_merge. Request-level failures (duplicate paths in one batch, idempotency key reused with a different payload, >200 items, >4MB) return 4xx and apply NOTHING. Each item MUST carry `content_sha` (SHA1 hex of the decoded body, same algorithm as git_sha) — it powers both the integrity check and the retry-safe `skipped_identical` result. Newly created .md items may carry `dedup_candidates` (same merge/skip/store advisory as sync_push); a batch creating more than 10 new files skips the check entirely and reports `dedup_skipped: "bulk"`.

## Request body

- object
  - `items` object[], required: Up to 200 push items, 4MB total, one entry per unique path. Duplicate paths reject the whole batch.
    - `path` string, required: Relative file path. No leading slash, no '..'.
    - `content` string: Full file content. May use the '__B64__:' prefix like sync_push.
    - `content_b64` string: Optional base64 body (use INSTEAD of content) for WAF bypass. Wins over content if both are present.
    - `content_sha` string, required: REQUIRED. SHA1 hex of the decoded content. Mismatch fails this item only (status 'error'); equality with the current remote git_sha yields 'skipped_identical' instead of a conflict, which is what makes a crashed batch safe to retry.
    - `base_sha` string: Same tri-state semantics as sync_push: omit for legacy LWW, null to assert the path does not exist yet, or the last observed git_sha for CAS.
    - `resolves_conflict_id` string: Optional vault_conflicts UUID this item closes. Requires a non-null base_sha and force=false.
    - `force` boolean: Optional per-item CAS bypass (audited). Suppresses the skipped_identical short-circuit.
    - `device_id` string: Optional per-item device id; falls back to the batch-level device_id.
  - `idempotency_key` string, required: REQUIRED. Opaque client-generated UUID, one per batch ATTEMPT-SET: reuse the same key when retrying the same items after a timeout (the server replays the stored results instead of re-applying), and generate a NEW key whenever the items change. Reusing a key with a different payload is a 400 collision, never a silent replay. Do not derive it from paths or content.
  - `device_id` string: Optional batch-level device identifier; per-item device_id overrides it.
  - `supports_superseded` boolean: Same capability opt-in as sync_push, applied to every item in the batch.

## Response `200`

Tool executed successfully

- ToolSuccessResponse: Successful tool invocation. `content` mirrors the MCP `tools/call` result shape: an array of content blocks (text and optionally a structured resource payload).
  - `content` object[]
    - `type` 'text' | 'resource'
    - `text` string

## Other responses

- `400`: Invalid arguments or business-rule violation
- `401`: Missing or invalid McpKey

---

[API](https://skmtc.dev/ainote/apis/ainote-mcp-openapi-mirror.md) · [All operations](https://skmtc.dev/ainote/apis/ainote-mcp-openapi-mirror/llms.txt) · [OpenAPI document](https://skmtc.dev/ainote/apis/ainote-mcp-openapi-mirror/revisions/f6c91d85e027?raw)
