Slug Collision Check
marketing.slug_collision_check
Overview
You send a slug and the slugs you already have, and we tell you whether it clashes and which alternatives are free. The comparison is entirely yours to set: a normalisation form, whether case is folded, and whether trailing separators count — and whatever you pick is applied to your candidate and to every entry alike, then compared code point for code point. Where there is a clash you get numbered alternatives, generated by a published rule and checked against the same set, so the first one you take is free. We do not generate a slug from a title and we do not reserve anything: the set we compare against is the one you sent.
Slug generators stop at the character rules and leave the interesting half to you: whether the result is taken, and what to call it if it is. Doing that by hand means reimplementing a normalisation form, a case fold and a numbering loop, and getting one of them subtly different from the database that stores the answer.
Reliability
Fully deterministic: the same candidate, set and policy give you the same verdict and the same alternatives, in the same order, under any locale. Failures, and what to do about each: SLUG_INPUT_INVALID means the candidate is empty or carries a control character, so clean it before asking; SLUG_TOO_LONG means the candidate is past 128 code points, which is longer than any slug generator here produces, so shorten it; SLUG_EXISTING_INVALID means an entry of the set is not a non-empty string, and the details carry its index so you can find it; SLUG_EXISTING_LIMIT_EXCEEDED means you sent more than 10000 entries, so narrow the set to the section the slug has to be unique within; SLUG_EXISTING_ELEMENT_TOO_LONG means an entry is past 128 code points, and again the details carry the index rather than the slug; SLUG_SEPARATOR_UNSUPPORTED means separator is neither HYPHEN nor UNDERSCORE, and no other character is accepted; SLUG_COMPARISON_OPTION_UNSUPPORTED means the comparison object carries a property we do not know or a value of the wrong shape, so correct it rather than expect a default; SLUG_SUFFIX_SCHEME_UNSUPPORTED means suffixScheme is not one of the two numbering schemes listed; SLUG_SUGGESTION_COUNT_INVALID means suggestionCount is not a whole number between 0 and 20, so pick one in range; SLUG_LENGTH_LIMIT_INVALID means maxSlugLength is out of range, or too small for any suffixed candidate to fit, so raise it or ask for no suggestions; SLUG_PROBE_LIMIT_INVALID means maxProbes is not a whole number between 1 and 10000, so pick one in range. None of these is worth retrying unchanged.
Context footprint
Returns a verdict, an index into the array you sent, and at most twenty short strings. Your set is never echoed back. A successful call costs 1 execution credit.
When to use it
When you have a candidate slug and the set it has to be free of, and you want alternatives when it is not.
When you still need to turn a title into a slug, or when only a unique index can answer the question you are really asking.
Scope
Non-goals
- Does not generate a slug from a title — text.slugify owns that half
- Does not guarantee uniqueness: the set compared against is the one you sent, and the unique index in your store is what actually enforces it
- Does not reserve, lock or remember a suggestion, so two callers asking at the same moment get the same answer
- Does not read any storage, and takes no separator character from you
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- This skill does not target sensitive data.
- The response may contain submitted or transformed content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| slug | string | Yes | Candidate slug, 1 through 128 code points, with no control characters. |
| existing | array | Yes | Slugs you already have, 0 through 10,000 entries; send empty to check only whether the candidate is well formed. |
| separator | string | No | Character that joins a numeric suffix; omit it for HYPHEN. |
| comparison | object | No | Optional comparison policy for case folding, unicode form, and trailing-separator trimming; omit it for caseFold true, NFC, and trimTrailingSeparators true. |
| suggestionCount | integer | No | How many alternatives to propose, from 0 through 20; omit it for 5. |
| suffixScheme | string | No | How numbered alternatives are generated; omit it for NUMERIC_INCREMENT. |
| maxSlugLength | integer | No | Maximum alternative length from 1 through 128; omit it for 128. |
| maxProbes | integer | No | Maximum numbering probes from 1 through 10,000; omit it for 10000. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| available | boolean | Yes | True when the candidate matches no existing entry under the comparison policy. |
| normalizedSlug | string | Yes | Candidate after the comparison policy was applied, so the verdict explains what was compared. |
| collisionIndex | integer | No | Zero-based index of the first matching existing entry; omitted when the candidate is available. |
| suggestions | array | Yes | Alternative slugs in probe order, empty when the candidate is available or you asked for none. |
| summary | object | Yes | Closed collision counters for existing-set size, duplicates, probes, whether suggestions ran out, and the separator, scheme, length, and comparison actually used. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"marketing.slug_collision_check","input":{"slug":"spring-launch","existing":["spring-launch"]}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("marketing.slug_collision_check", {"slug":"spring-launch","suggestionCount":3,"existing":["spring-launch","autumn-launch"]});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| SLUG_INPUT_INVALID | 400 | No | The request payload failed this skill's input validation. |
| SLUG_TOO_LONG | 429 | No | A size, quota, rate, or time limit was exceeded. |
| SLUG_EXISTING_INVALID | 400 | No | The request payload failed this skill's input validation. |
| SLUG_EXISTING_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| SLUG_EXISTING_ELEMENT_TOO_LONG | 429 | No | A size, quota, rate, or time limit was exceeded. |
| SLUG_SEPARATOR_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| SLUG_COMPARISON_OPTION_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| SLUG_SUFFIX_SCHEME_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| SLUG_SUGGESTION_COUNT_INVALID | 400 | No | The request payload failed this skill's input validation. |
| SLUG_LENGTH_LIMIT_INVALID | 400 | No | The request payload failed this skill's input validation. |
| SLUG_PROBE_LIMIT_INVALID | 400 | No | The request payload failed this skill's input validation. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not generate a slug from a title — text.slugify owns that half
- Does not guarantee uniqueness: the set compared against is the one you sent, and the unique index in your store is what actually enforces it
- Does not reserve, lock or remember a suggestion, so two callers asking at the same moment get the same answer
- Does not read any storage, and takes no separator character from you
- Turning a title into a slug in the first place
- Guaranteeing a slug will still be free when the insert runs
- Checking against a set too large to send, such as a whole catalogue
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "marketing.slug_collision_check",
"input": {
"slug": "spring-launch",
"suggestionCount": 3,
"existing": [
"spring-launch",
"autumn-launch"
]
}
}Examples
Suggest alternatives for a slug an editor reused
{
"slug": "spring-launch",
"suggestionCount": 3,
"existing": [
"spring-launch",
"autumn-launch"
]
}{
"available": false,
"collisionIndex": 0,
"suggestions": [
"spring-launch-2",
"spring-launch-3",
"spring-launch-4"
],
"normalizedSlug": "spring-launch",
"summary": {
"existingCount": 2,
"distinctExistingCount": 2,
"duplicateExistingCount": 0,
"probes": 3,
"suggestionsExhausted": false,
"separator": "hyphen",
"suffixScheme": "numeric_increment",
"maxSlugLength": 128,
"comparison": {
"trimTrailingSeparators": true,
"caseFold": true,
"unicodeForm": "nfc"
}
}
}Confirm a slug is free, case folding switched off
{
"existing": [
"spring-launch"
],
"suggestionCount": 0,
"comparison": {
"caseFold": false
},
"slug": "Spring-Launch"
}{
"summary": {
"existingCount": 1,
"distinctExistingCount": 1,
"duplicateExistingCount": 0,
"probes": 0,
"suggestionsExhausted": false,
"separator": "hyphen",
"suffixScheme": "numeric_increment",
"maxSlugLength": 128,
"comparison": {
"trimTrailingSeparators": true,
"caseFold": false,
"unicodeForm": "nfc"
}
},
"suggestions": [],
"available": true,
"normalizedSlug": "Spring-Launch"
}Recommended use cases
- Check an article or product slug against the ones a section already holds, before showing the author a save button
- Offer numbered alternatives when an editor picks a title that has been used
- Compare slugs the way a store compares them, by matching the normalisation form and case folding to the column collation
Avoid for
- Turning a title into a slug in the first place
- Guaranteeing a slug will still be free when the insert runs
- Checking against a set too large to send, such as a whole catalogue
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.