Derive a URL slug from a Git branch name
Convert a Git branch name such as feature/add-user-login into a concise, URL-friendly slug without carrying the workflow prefix into the result.
Run — free
The capability recognizes the first path segment as the branch type, keeps everything after it as the descriptive portion, and normalizes that portion into lowercase words separated by hyphens. It is deterministic, requires no network access, and reports a clear input error when the branch contains a prefix but no usable description.
Separate workflow metadata from the useful description
Git teams commonly begin branch names with a workflow type such as feature, fix, chore, release, or docs. That first segment helps people and automation understand why a branch exists, but it is usually noise in a public URL. This capability treats the text before the first slash as the type prefix and derives the slug only from everything that follows. For example, feature/add-user-login becomes add-user-login, while fix/checkout/payment-timeout becomes checkout-payment-timeout. Nested descriptive paths are preserved as words rather than discarded, so teams can retain meaningful scopes without exposing slash characters in the final URL. An optional refs/heads/ prefix, often returned by Git tooling and continuous integration systems, is removed before the branch is interpreted. The operation does not maintain a private list of accepted branch types. Any nonempty first segment can serve as the prefix, which lets the same rule work with local conventions such as spike, experiment, maintenance, or a ticket workflow defined by your own organization.
Understand exactly how the slug is normalized
After selecting the descriptive portion, the algorithm applies a stable sequence of transformations. It trims surrounding whitespace, normalizes accented Latin characters, converts letters to lowercase, replaces every run of characters outside ASCII letters and digits with one hyphen, and removes hyphens from the beginning and end. Slashes, spaces, underscores, punctuation, and repeated separators therefore converge on the same URL-safe form. A branch such as feature/Account Settings_v2 becomes account-settings-v2. The result is intentionally predictable: there is no language model, dictionary, network lookup, random value, timestamp, or repository state involved. The function does not invent words or try to interpret issue identifiers. Numbers already present in the description remain present, which is useful for names such as fix/PROJ-482-login-loop. Because normalization can remove symbols and unsupported scripts, the capability also verifies that at least one usable letter or number remains. If the descriptive portion consists entirely of punctuation or characters that cannot form the supported ASCII slug, it returns an input error instead of silently producing an empty value.
Use the result safely in publishing and automation
The returned object contains one field, slug, so it can feed directly into a documentation preview, ephemeral environment URL, release-note path, changelog page, or pull-request publishing workflow. Validate the result before reserving a route if your destination has additional rules, such as a maximum length, a list of protected paths, or a uniqueness requirement. This capability deliberately does not query your router, hosting provider, Git service, or content database, so it cannot know whether the derived slug is already occupied. It also does not validate whether the supplied string is an existing branch in a repository; it only applies the documented branch-name convention. Branch names without a slash, names ending immediately after the type prefix, and descriptions that normalize to an empty slug are rejected. That strict failure behavior is valuable in automation because a malformed source cannot accidentally publish to a blank or generic route. For API automation, each request uses the published base price of $0.002. The same deterministic transformation can run in the browser for quick individual conversions.
What you can do with it
Name a preview deployment
Turn a feature branch into a readable path for an isolated review environment without including the workflow prefix.
Create a release-note path
Derive a consistent URL segment from the descriptive part of a release or fix branch for generated notes.
Standardize pull-request links
Normalize nested branch descriptions into stable lowercase links used by documentation and project automation.
FAQ
What counts as the type prefix?
The first nonempty segment before the first slash. It can be feature, fix, chore, or any type name used by your team.
What happens to nested branch paths?
All segments after the first slash belong to the description, and their separators become hyphens in the slug.
Can I pass a full refs/heads name?
Yes. A leading refs/heads/ is removed before the type prefix and descriptive portion are identified.
Why does a branch without a slash fail?
The capability requires a distinct type prefix and descriptive portion, so a single unseparated name is ambiguous.
Does this check whether the branch exists?
No. It performs deterministic text processing only and never connects to a repository or Git hosting service.
What does an API request cost?
Each API request uses the published base price of $0.002; the browser version can perform the same transformation locally.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev/slug-from-git-branch \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"branch":"feature/add-user-login"}'const res = await fetch("https://api.kit.forhosting.com/dev/slug-from-git-branch", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"branch": "feature/add-user-login"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev/slug-from-git-branch",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"branch": "feature/add-user-login"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev/slug-from-git-branch", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"branch":"feature/add-user-login"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"branch":"feature/add-user-login"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev/slug-from-git-branch", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"branch": "feature/add-user-login"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev.slug_from_git_branch",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |