Skip to content

API Reference

Refringe edited this page Mar 8, 2026 · 1 revision

API Reference

Anchor LFS implements the Git LFS Batch API and the File Locking API. This page documents all HTTP endpoints.

All LFS endpoints are registered per-endpoint at the configured path prefix. For an endpoint configured as endpoint = "/org/repo", the batch endpoint would be /org/repo/objects/batch.

Content Types

LFS API requests and responses use:

Content-Type: application/vnd.git-lfs+json
Accept: application/vnd.git-lfs+json

The server validates media types strictly and rejects requests with incorrect content types.

Server Endpoints

Health Check

GET /health

Returns server status and version. Not rate limited.

Response:

{
  "status": "ok",
  "version": "v1.0.0"
}

Root

GET /

Returns version information. Not rate limited.

Response:

{
  "version": "v1.0.0"
}

Batch API

Transfer Negotiation

POST {prefix}/objects/batch

Negotiate downloads or uploads for one or more objects. Rate limited.

Request:

{
  "operation": "download",
  "transfers": ["basic"],
  "hash_algo": "sha256",
  "ref": {
    "name": "refs/heads/main"
  },
  "objects": [
    {
      "oid": "abc123def456...",
      "size": 12345678
    }
  ]
}
Field Required Description
operation Yes "download" or "upload"
transfers No Transfer adapters the client supports. Only "basic" is supported.
hash_algo No Hash algorithm. Only "sha256" is supported.
ref No Git ref for the request. Accepted for spec compliance but Anchor LFS authorises at repository level, not per-branch.
objects Yes Array of objects to download or upload. Maximum 1000 per request.

Response:

{
  "transfer": "basic",
  "objects": [
    {
      "oid": "abc123def456...",
      "size": 12345678,
      "authenticated": true,
      "actions": {
        "download": {
          "href": "https://lfs.example.com/org/repo/objects/abc123def456...?exp=1709990400&sig=base64sig",
          "expires_in": 600,
          "expires_at": "2026-03-09T12:00:00Z"
        }
      }
    }
  ],
  "hash_algo": "sha256"
}

Action types returned:

Action When Description
download Download operation, object exists URL to download the object
upload Upload operation, object doesn't exist URL to upload the object
verify Upload operation, object doesn't exist URL to verify the upload (called after upload)

Error responses per object:

If an individual object has an error (e.g., not found during download, exceeds max size during upload), the response includes an error field instead of actions:

{
  "oid": "abc123...",
  "size": 12345678,
  "error": {
    "code": 404,
    "message": "object not found"
  }
}

Object Transfer

Download Object

GET {prefix}/objects/{oid}

Download an LFS object. Rate limited. Requires a valid HMAC signature on the URL.

Features:

  • Range requests: Supports the Range header for resumable downloads (when using local storage)
  • ETags: Returns the OID as the ETag header for caching
  • Content-Type: application/octet-stream

URL Parameters:

Parameter Description
exp Expiration timestamp (Unix epoch)
sig Base64-encoded HMAC-SHA256 signature

Upload Object

PUT {prefix}/objects/{oid}

Upload an LFS object. Not rate limited. Requires a valid HMAC signature on the URL.

Request Headers:

Header Required Description
Content-Length Yes Size of the upload in bytes. Must match the declared size.
Content-Type No Should be application/octet-stream or omitted.

Upload Process:

  1. The server streams the request body to storage
  2. SHA-256 hash is computed during the upload
  3. If the hash doesn't match the OID, the object is deleted and a 400 error is returned
  4. On success, returns 200 OK

Verify Upload

POST {prefix}/objects/verify

Verify that an uploaded object was stored correctly. Rate limited.

Request:

{
  "oid": "abc123def456...",
  "size": 12345678
}

Response:

  • 200 OK: Object exists and size matches
  • 404 Not Found: Object not found
  • 422 Unprocessable Entity: Size mismatch

File Locking API

Create Lock

POST {prefix}/locks

Create a file lock. Rate limited.

Request:

{
  "path": "assets/model.bin",
  "ref": {
    "name": "refs/heads/main"
  }
}

Response (201 Created):

{
  "lock": {
    "id": "unique-lock-id",
    "path": "assets/model.bin",
    "locked_at": "2026-03-09T12:34:56Z",
    "owner": {
      "name": "username"
    }
  }
}

Error (409 Conflict): Returned if the file is already locked.

List Locks

GET {prefix}/locks

List file locks. Rate limited.

Query Parameters:

Parameter Description
path Filter by file path
id Filter by lock ID
cursor Pagination cursor from a previous response
limit Maximum number of locks to return (default: 100, max: 1000)
refspec Git ref (accepted for compatibility)

Response:

{
  "locks": [
    {
      "id": "unique-lock-id",
      "path": "assets/model.bin",
      "locked_at": "2026-03-09T12:34:56Z",
      "owner": {
        "name": "username"
      }
    }
  ],
  "next_cursor": ""
}

Verify Locks

POST {prefix}/locks/verify

List locks, separated into "ours" (owned by the authenticated user) and "theirs" (owned by others). Rate limited.

Request:

{
  "cursor": "",
  "limit": 100,
  "ref": {
    "name": "refs/heads/main"
  }
}

Response:

{
  "ours": [
    {
      "id": "lock-id-1",
      "path": "assets/our-file.bin",
      "locked_at": "2026-03-09T12:00:00Z",
      "owner": {
        "name": "our-username"
      }
    }
  ],
  "theirs": [
    {
      "id": "lock-id-2",
      "path": "assets/their-file.bin",
      "locked_at": "2026-03-09T11:00:00Z",
      "owner": {
        "name": "other-username"
      }
    }
  ],
  "next_cursor": ""
}

Unlock

POST {prefix}/locks/{id}/unlock

Release a file lock. Rate limited.

Request:

{
  "force": false
}

Set force to true to override lock ownership and unlock a file locked by another user.

Response (200 OK):

{
  "lock": {
    "id": "unique-lock-id",
    "path": "assets/model.bin",
    "locked_at": "2026-03-09T12:34:56Z",
    "owner": {
      "name": "username"
    }
  }
}

Common Response Headers

Header Description
X-Request-ID Unique request identifier for log correlation
Content-Type application/vnd.git-lfs+json for LFS responses

HTTP Status Codes

Code Meaning
200 Success
201 Created (lock created)
400 Bad request (invalid JSON, hash mismatch, etc.)
401 Unauthorised (missing or invalid credentials)
403 Forbidden (insufficient permissions)
404 Not found
409 Conflict (lock already exists)
413 Payload too large (exceeds max_upload_size)
422 Unprocessable entity (size mismatch on verify)
429 Too many requests (rate limit exceeded, includes Retry-After header)
500 Internal server error
507 Insufficient storage (disk full)

Request Limits

Limit Value
Maximum objects per batch request 1000
Maximum JSON request body 1 MB
Maximum upload size Configurable (default: 5 GiB)

Next Steps

Clone this wiki locally