-
-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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.
GET /health
Returns server status and version. Not rate limited.
Response:
{
"status": "ok",
"version": "v1.0.0"
}GET /
Returns version information. Not rate limited.
Response:
{
"version": "v1.0.0"
}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"
}
}GET {prefix}/objects/{oid}
Download an LFS object. Rate limited. Requires a valid HMAC signature on the URL.
Features:
-
Range requests: Supports the
Rangeheader for resumable downloads (when using local storage) -
ETags: Returns the OID as the
ETagheader for caching -
Content-Type:
application/octet-stream
URL Parameters:
| Parameter | Description |
|---|---|
exp |
Expiration timestamp (Unix epoch) |
sig |
Base64-encoded HMAC-SHA256 signature |
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:
- The server streams the request body to storage
- SHA-256 hash is computed during the upload
- If the hash doesn't match the OID, the object is deleted and a
400error is returned - On success, returns
200 OK
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
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.
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": ""
}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": ""
}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"
}
}
}| Header | Description |
|---|---|
X-Request-ID |
Unique request identifier for log correlation |
Content-Type |
application/vnd.git-lfs+json for LFS responses |
| 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) |
| Limit | Value |
|---|---|
| Maximum objects per batch request | 1000 |
| Maximum JSON request body | 1 MB |
| Maximum upload size | Configurable (default: 5 GiB) |
- Git LFS Client Setup: Configure clients
- File Locking: Locking details
- Security: URL signing and rate limiting