Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Slug Collision Check

marketing.slug_collision_check

ProductionBounded custom (Class B)Deterministicstrictinstantv1.0.0
No network

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

Note
Decide whether a candidate slug collides with a caller-supplied set under a published comparison policy, and propose collision-free alternatives.

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

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

generationvalidation

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input2 MB

How we handle your data

Sensitive output possible
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.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
slugstringYesCandidate slug, 1 through 128 code points, with no control characters.
existingarrayYesSlugs you already have, 0 through 10,000 entries; send empty to check only whether the candidate is well formed.
separatorstringNoCharacter that joins a numeric suffix; omit it for HYPHEN.
comparisonobjectNoOptional comparison policy for case folding, unicode form, and trailing-separator trimming; omit it for caseFold true, NFC, and trimTrailingSeparators true.
suggestionCountintegerNoHow many alternatives to propose, from 0 through 20; omit it for 5.
suffixSchemestringNoHow numbered alternatives are generated; omit it for NUMERIC_INCREMENT.
maxSlugLengthintegerNoMaximum alternative length from 1 through 128; omit it for 128.
maxProbesintegerNoMaximum numbering probes from 1 through 10,000; omit it for 10000.

Output schema

FieldTypeRequiredDescription
availablebooleanYesTrue when the candidate matches no existing entry under the comparison policy.
normalizedSlugstringYesCandidate after the comparison policy was applied, so the verdict explains what was compared.
collisionIndexintegerNoZero-based index of the first matching existing entry; omitted when the candidate is available.
suggestionsarrayYesAlternative slugs in probe order, empty when the candidate is available or you asked for none.
summaryobjectYesClosed 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/execute
curl
curl -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"]}}'
Integrations
TypeScript SDK
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

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
SLUG_INPUT_INVALID400NoThe request payload failed this skill's input validation.
SLUG_TOO_LONG429NoA size, quota, rate, or time limit was exceeded.
SLUG_EXISTING_INVALID400NoThe request payload failed this skill's input validation.
SLUG_EXISTING_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
SLUG_EXISTING_ELEMENT_TOO_LONG429NoA size, quota, rate, or time limit was exceeded.
SLUG_SEPARATOR_UNSUPPORTED400NoThe skill does not support the requested variant.
SLUG_COMPARISON_OPTION_UNSUPPORTED400NoThe skill does not support the requested variant.
SLUG_SUFFIX_SCHEME_UNSUPPORTED400NoThe skill does not support the requested variant.
SLUG_SUGGESTION_COUNT_INVALID400NoThe request payload failed this skill's input validation.
SLUG_LENGTH_LIMIT_INVALID400NoThe request payload failed this skill's input validation.
SLUG_PROBE_LIMIT_INVALID400NoThe request payload failed this skill's input validation.

Other limits

LimitValue
Recommended inline bytes32 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)

Request bodyjson
{
  "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

Inputjson
{
  "slug": "spring-launch",
  "suggestionCount": 3,
  "existing": [
    "spring-launch",
    "autumn-launch"
  ]
}
Expected outputjson
{
  "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"
    }
  }
}
Tip
Numbering starts at 2 by default and skips anything already in the set, so the first suggestion you take is free.

Confirm a slug is free, case folding switched off

Inputjson
{
  "existing": [
    "spring-launch"
  ],
  "suggestionCount": 0,
  "comparison": {
    "caseFold": false
  },
  "slug": "Spring-Launch"
}
Expected outputjson
{
  "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"
}
Tip
With folding off the capitals make it a different slug, which is the right answer for a store that compares raw bytes.
  • 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

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.

Tags

normalizationmarketingvalidationslug