Skip to main content
Create a commit by streaming file contents as newline-delimited JSON.
POST /api/v1/repos/commit-pack
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/x-ndjson

Request Format

The body is newline-delimited JSON. Send metadata first, followed by one or more blob chunks.
{"metadata":{"target_branch":"main","expected_head_sha":"d34db33fd34db33fd34db33fd34db33f","commit_message":"Update docs","author":{"name":"Docs Bot","email":"docs@example.com"},"files":[{"path":"docs/changelog.md","operation":"upsert","content_id":"blob-1","mode":"100644"},{"path":"docs/legacy.txt","operation":"delete","content_id":"blob-2"}]}}
{"blob_chunk":{"content_id":"blob-1","data":"IyBWZXJzaW9uIDIuMS4wCi0gcmVmcmVzaCBkb2NzCg==","eof":true}}
{"blob_chunk":{"content_id":"blob-2","data":"","eof":true}}

Request Body Fields

ParameterTypeDescription
target_branchRequiredBranch name (for example main)
commit_messageRequiredThe commit message
authorRequiredObject with name and email
filesRequiredArray of file operations (see below)
expected_head_shaOptionalCommit SHA that must match the branch tip before writing; omit to fast-forward unconditionally
base_branchOptionalSource branch to copy when target_branch does not exist. If you also provide expected_head_sha, it must match the source branch head; otherwise the branch is created from the latest base branch commit
committerOptionalObject with name and email
ephemeralOptionalWhen true, write the target branch under the ephemeral namespace
ephemeral_baseOptionalWhen true, interpret base_branch as ephemeral

File Operations

  • path (required): Repository-relative path; leading slashes are stripped
  • operation: upsert (default) to add or replace content, delete to remove a file
  • content_id (required): Identifier that blob chunks reference
  • mode (optional): File mode such as 100644 or 100755
  • For delete operations, omit blob chunks—only the metadata entry is required

Blob Chunks

  • Each line after the metadata must contain a blob_chunk object
  • content_id ties the chunk to a file operation
  • data is base64 encoded; decoded chunks must be 4 MiB or smaller
  • Use multiple blob_chunk messages per file for streaming; mark the last chunk with "eof": true
  • Empty files should send an EOF chunk with an empty base64 string

JWT Requirements

  • The JWT must include the repository in the repo claim
  • Requires git:write scope

Response

{
  "commit": {
    "commit_sha": "8f12c3bd0f4ff7bfb7267e7a61b3c4a8712a10b2",
    "tree_sha": "b9532c5d5be50d88e2f45d7c229566b2f1f99731",
    "target_branch": "main",
    "pack_bytes": 5421,
    "blob_count": 2
  },
  "result": {
    "branch": "main",
    "old_sha": "c4f0fdfc41adab56630b34f5f4fd4e84a2c5b4d2",
    "new_sha": "8f12c3bd0f4ff7bfb7267e7a61b3c4a8712a10b2",
    "success": true,
    "status": "ok",
    "message": ""
  }
}

Notes

  • Successful requests return 201 Created; validation errors return 4xx codes with error details
  • Use the SDK’s repo.createCommit() helper for streaming, chunking, and authentication automatically
  • The target_branch must already exist unless you include base_branch, in which case the service creates the target branch from that source branch when it is missing
  • If you passed an expected_head_sha, the service verifies it matches the source branch head before creating the new branch
  • Repositories with no refs can still omit expected_head_sha to seed their default branch
  • Pair expected_head_sha with a commit SHA to enforce fast-forward semantics during migrations or CI jobs
  • result.old_sha is always a 40-character hex string reflecting the previous tip; it is 0000000000000000000000000000000000000000 when the target branch did not previously exist

Error Responses

StatusDescription
401 UnauthorizedInvalid JWT or missing git:write scope
400 Bad RequestInvalid request format, missing required fields, or blob chunk validation errors
409 ConflictExpected head SHA doesn’t match current branch tip
404 Not FoundBase branch doesn’t exist (when creating new target branch)