REST API
Use the Artifacts REST API to manage repos, remotes, forks, imports, and tokens from external systems.
Artifacts REST routes use this base path:
https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/artifacts/namespaces/$ARTIFACTS_NAMESPACERequests to /v1/api/... use Bearer authentication:
Authorization: Bearer <CLOUDFLARE_API_TOKEN>All routes below are relative to this base URL.
Cloudflare API tokens authenticate REST control-plane routes. Repo tokens authenticate Git operations against the returned remote URL.
The following examples assume:
export ACCOUNT_ID="<YOUR_ACCOUNT_ID>"export ARTIFACTS_NAMESPACE="default"export ARTIFACTS_REPO="starter-repo"export CLOUDFLARE_API_TOKEN="<YOUR_API_TOKEN>"export ARTIFACTS_BASE_URL="https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/artifacts/namespaces/$ARTIFACTS_NAMESPACE"All responses use the standard Cloudflare v4 envelope.
Returned repo tokens are secrets. Do not log them or store them in long-lived remotes unless your workflow requires it.
export type NamespaceName = string;export type RepoName = string;export type BranchName = string;export type Scope = "read" | "write";export type TokenState = "active" | "expired" | "revoked";export type ArtifactToken = string;export type Cursor = string;export type RepoSortField = | "created_at" | "updated_at" | "last_push_at" | "name";export type SortDirection = "asc" | "desc";
export interface ApiError { code: number; message: string; documentation_url?: string; source?: { pointer?: string; };}
export interface CursorResultInfo { cursor: string; per_page: number; count: number;}
export interface OffsetResultInfo { page: number; per_page: number; total_pages: number; count: number; total_count: number;}
export type ResultInfo = CursorResultInfo | OffsetResultInfo;
export interface ApiEnvelope<T> { result: T | null; success: boolean; errors: ApiError[]; messages: ApiError[]; result_info?: ResultInfo;}
export interface RepoInfo { id: string; name: RepoName; description: string | null; default_branch: string; created_at: string; updated_at: string; last_push_at: string | null; source: string | null; read_only: boolean;}
export interface RemoteRepoInfo extends RepoInfo { remote: string;}
export interface TokenInfo { id: string; scope: Scope; state: TokenState; created_at: string; expires_at: string;}Route: POST /repos
Request body:
nameRepoNamerequireddescriptionstringoptionaldefault_branchBranchNameoptionalread_onlybooleanoptional
Response type:
export interface CreateRepoRequest { name: RepoName; description?: string; default_branch?: BranchName; read_only?: boolean;}
export interface CreateRepoResult { id: string; name: RepoName; description: string | null; default_branch: string; remote: string; token: ArtifactToken;}
export type CreateRepoResponse = ApiEnvelope<CreateRepoResult>;curl --request POST "$ARTIFACTS_BASE_URL/repos" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --header "Content-Type: application/json" \ --data '{ "name": "starter-repo", "description": "Repository for automation experiments", "default_branch": "main", "read_only": false }'{ "result": { "id": "repo_123", "name": "starter-repo", "description": "Repository for automation experiments", "default_branch": "main", "remote": "https://<ACCOUNT_ID>.artifacts.cloudflare.net/git/default/starter-repo.git", "token": "art_v1_0123456789abcdef0123456789abcdef01234567?expires=1760000000" }, "success": true, "errors": [], "messages": []}Route: GET /repos?limit=&cursor=&search=&sort=&direction=
Query parameters:
limitnumberoptional (default: 50, max: 200)cursorCursoroptionalsearchstringoptionalsort"created_at" | "updated_at" | "last_push_at" | "name"optional (default: "created_at")direction"asc" | "desc"optional (default: "desc")
Response type:
export interface ListReposQuery { limit?: number; cursor?: Cursor; search?: string; sort?: RepoSortField; direction?: SortDirection;}
export type ListReposResponse = ApiEnvelope<RepoInfo[]>;curl "$ARTIFACTS_BASE_URL/repos?limit=20&sort=updated_at&direction=desc" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"{ "result": [ { "id": "repo_123", "name": "starter-repo", "description": "Repository for automation experiments", "default_branch": "main", "created_at": "<ISO_TIMESTAMP>", "updated_at": "<ISO_TIMESTAMP>", "last_push_at": "<ISO_TIMESTAMP>", "source": null, "read_only": false } ], "success": true, "errors": [], "messages": [], "result_info": { "cursor": "next-cursor", "per_page": 20, "count": 1 }}Route: GET /repos/:name
Response type:
export type GetRepoResponse = ApiEnvelope<RemoteRepoInfo>;curl "$ARTIFACTS_BASE_URL/repos/$ARTIFACTS_REPO" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"{ "result": { "id": "repo_123", "name": "starter-repo", "description": "Repository for automation experiments", "default_branch": "main", "created_at": "<ISO_TIMESTAMP>", "updated_at": "<ISO_TIMESTAMP>", "last_push_at": "<ISO_TIMESTAMP>", "source": null, "read_only": false, "remote": "https://<ACCOUNT_ID>.artifacts.cloudflare.net/git/default/starter-repo.git" }, "success": true, "errors": [], "messages": []}Route: DELETE /repos/:name
This route returns 202 Accepted.
Response type:
export interface DeleteRepoResult { id: string;}
export type DeleteRepoResponse = ApiEnvelope<DeleteRepoResult>;curl --request DELETE "$ARTIFACTS_BASE_URL/repos/$ARTIFACTS_REPO" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"{ "result": { "id": "repo_123" }, "success": true, "errors": [], "messages": []}Route: POST /repos/:name/fork
Request body:
nameRepoNamerequireddescriptionstringoptionalread_onlybooleanoptionaldefault_branch_onlybooleanoptional
Response type:
export interface ForkRepoRequest { name: RepoName; description?: string; read_only?: boolean; default_branch_only?: boolean;}
export interface ForkRepoResult extends CreateRepoResult { objects: number;}
export type ForkRepoResponse = ApiEnvelope<ForkRepoResult>;curl --request POST "$ARTIFACTS_BASE_URL/repos/$ARTIFACTS_REPO/fork" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --header "Content-Type: application/json" \ --data '{ "name": "starter-repo-copy", "description": "Fork for testing", "read_only": false, "default_branch_only": true }'{ "result": { "id": "repo_456", "name": "starter-repo-copy", "description": "Repository for automation experiments", "default_branch": "main", "remote": "https://<ACCOUNT_ID>.artifacts.cloudflare.net/git/default/starter-repo-copy.git", "token": "art_v1_89abcdef0123456789abcdef0123456789abcdef?expires=1760003600", "objects": 128 }, "success": true, "errors": [], "messages": []}Route: POST /repos/:name/import
Request body:
urlstringrequiredbranchstringoptionaldepthnumberoptionalread_onlybooleanoptional
Response type:
export interface ImportRepoRequest { url: string; branch?: string; depth?: number; read_only?: boolean;}
export type ImportRepoResponse = ApiEnvelope<CreateRepoResult>;Pass a full HTTPS Git remote URL, for example https://github.com/facebook/react or https://gitlab.com/group/project.git.
curl --request POST "$ARTIFACTS_BASE_URL/repos/react-mirror/import" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --header "Content-Type: application/json" \ --data '{ "url": "https://github.com/facebook/react", "branch": "main", "depth": 100 }'{ "result": { "id": "repo_789", "name": "react-mirror", "description": null, "default_branch": "main", "remote": "https://<ACCOUNT_ID>.artifacts.cloudflare.net/git/default/react-mirror.git", "token": "art_v1_fedcba9876543210fedcba9876543210fedcba98?expires=1760007200" }, "success": true, "errors": [], "messages": []}These tokens are for Git routes. They do not authenticate REST API requests.
Route: GET /repos/:name/tokens?state=&per_page=&page=
Query parameters:
state"active" | "expired" | "revoked" | "all"optional (default: "active")per_pagenumberoptional (default: 30, max: 100)pagenumberoptional (default: 1)
Response type:
export interface ListTokensQuery { state?: TokenState | "all"; per_page?: number; page?: number;}
export type ListTokensResponse = ApiEnvelope<TokenInfo[]>;curl "$ARTIFACTS_BASE_URL/repos/$ARTIFACTS_REPO/tokens?state=all&per_page=30&page=1" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"{ "result": [ { "id": "tok_123", "scope": "read", "state": "active", "created_at": "<ISO_TIMESTAMP>", "expires_at": "<ISO_TIMESTAMP>" } ], "success": true, "errors": [], "messages": [], "result_info": { "page": 1, "per_page": 30, "total_pages": 1, "count": 1, "total_count": 1 }}Route: POST /tokens
Request body:
repoRepoNamerequiredscope"read" | "write"optional (default: "write")ttlnumberoptional (seconds, default: 86400)
Response type:
export interface CreateTokenRequest { repo: RepoName; scope?: Scope; ttl?: number;}
export interface CreateTokenResult { id: string; plaintext: ArtifactToken; scope: Scope; expires_at: string;}
export type CreateTokenResponse = ApiEnvelope<CreateTokenResult>;curl --request POST "$ARTIFACTS_BASE_URL/tokens" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --header "Content-Type: application/json" \ --data '{ "repo": "starter-repo", "scope": "read", "ttl": 3600 }'{ "result": { "id": "tok_123", "plaintext": "art_v1_0123456789abcdef0123456789abcdef01234567?expires=1760000000", "scope": "read", "expires_at": "<ISO_TIMESTAMP>" }, "success": true, "errors": [], "messages": []}Route: DELETE /tokens/:id
Response type:
export interface RevokeTokenResult { id: string;}
export type RevokeTokenResponse = ApiEnvelope<RevokeTokenResult>;curl --request DELETE "$ARTIFACTS_BASE_URL/tokens/tok_123" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"{ "result": { "id": "tok_123" }, "success": true, "errors": [], "messages": []}Application errors also use the v4 envelope:
export interface ApiError { code: number; message: string; documentation_url?: string; source?: { pointer?: string; };}