Docs

Check Slug Availability

Check if a project slug is available before creating a project

Check Slug Endpoint

Validate whether a project slug is available for use in your organization. This endpoint is useful for providing real-time feedback in forms before attempting to create a project.

Endpoint

GET /api/projects/check-slug

Authentication

Requires authentication. Include your session token in the request headers:

Authorization: Bearer <session_token>

Query Parameters

ParameterTypeRequiredDescription
slugstringYesThe slug to check availability for
excludeIdstringNoProject ID to exclude from the check (useful when updating)

Request Examples

Check if a slug is available

curl -X GET "https://api.yourdomain.com/api/projects/check-slug?slug=my-new-project" \
  -H "Authorization: Bearer YOUR_TOKEN"

Check availability excluding current project (for updates)

curl -X GET "https://api.yourdomain.com/api/projects/check-slug?slug=my-new-project&excludeId=proj_123456789" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

Available Slug

{
  "success": true,
  "data": {
    "available": true,
    "slug": "my-new-project",
    "suggestions": []
  },
  "message": "Slug is available"
}

Unavailable Slug

{
  "success": true,
  "data": {
    "available": false,
    "slug": "my-project",
    "suggestions": [
      "my-project-2",
      "my-project-2024",
      "my-project-team"
    ]
  },
  "message": "Slug is not available"
}

Response Fields

FieldTypeDescription
availablebooleanWhether the slug can be used
slugstringThe slug that was checked
suggestionsarrayAlternative slug suggestions if unavailable

Slug Validation Rules

Slugs must follow these rules:

  • 3-63 characters in length
  • Only lowercase letters, numbers, and hyphens
  • Must start with a letter
  • Must end with a letter or number
  • Cannot contain consecutive hyphens
  • Must be unique per organization

Error Responses

Invalid Slug Format

{
  "success": false,
  "data": null,
  "error": {
    "code": "BAD_REQUEST",
    "message": "Invalid slug format. Slug must be 3-63 characters, lowercase letters, numbers, and hyphens only."
  }
}

Missing Slug Parameter

{
  "success": false,
  "data": null,
  "error": {
    "code": "BAD_REQUEST",
    "message": "Missing required parameter: slug"
  }
}

Unauthorized

{
  "success": false,
  "data": null,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Authentication required"
  }
}

Frontend Integration Example

import { useState, useEffect, useCallback } from 'react';
import { debounce } from 'lodash';

function useSlugCheck() {
  const [isAvailable, setIsAvailable] = useState<boolean | null>(null);
  const [suggestions, setSuggestions] = useState<string[]>([]);
  const [isChecking, setIsChecking] = useState(false);

  const checkSlug = useCallback(
    debounce(async (slug: string, excludeId?: string) => {
      if (!slug || slug.length < 3) {
        setIsAvailable(null);
        return;
      }

      setIsChecking(true);
      try {
        const params = new URLSearchParams({ slug });
        if (excludeId) params.append('excludeId', excludeId);

        const response = await fetch(`/api/projects/check-slug?${params}`, {
          headers: {
            'Authorization': `Bearer ${getToken()}`
          }
        });

        const result = await response.json();
        
        if (result.success) {
          setIsAvailable(result.data.available);
          setSuggestions(result.data.suggestions);
        }
      } finally {
        setIsChecking(false);
      }
    }, 300),
    []
  );

  return { isAvailable, suggestions, isChecking, checkSlug };
}

// Usage in a form component
function ProjectForm({ project }: { project?: Project }) {
  const [slug, setSlug] = useState(project?.slug || '');
  const { isAvailable, suggestions, isChecking, checkSlug } = useSlugCheck();

  useEffect(() => {
    checkSlug(slug, project?.id);
  }, [slug, project?.id, checkSlug]);

  return (
    <form>
      <div>
        <label>Project Slug</label>
        <input
          type="text"
          value={slug}
          onChange={(e) => setSlug(e.target.value)}
          placeholder="my-awesome-project"
        />
        {isChecking && <span>Checking availability...</span>}
        {!isChecking && isAvailable === true && (
          <span className="text-green-600">Available</span>
        )}
        {!isChecking && isAvailable === false && (
          <div>
            <span className="text-red-600">Not available</span>
            {suggestions.length > 0 && (
              <div>
                <p>Suggestions:</p>
                <ul>
                  {suggestions.map((s) => (
                    <li key={s}>
                      <button type="button" onClick={() => setSlug(s)}>
                        {s}
                      </button>
                    </li>
                  ))}
                </ul>
              </div>
            )}
          </div>
        )}
      </div>
    </form>
  );
}

Rate Limits

  • 60 requests per minute per user (higher than standard due to real-time validation use case)

Notes

  • The slug check is scoped to your organization. A slug may be unavailable in your organization but available globally.
  • Suggestions are generated by appending numbers, years, or common suffixes to the requested slug.
  • The excludeId parameter is useful when editing an existing project and you want to allow keeping the current slug.

On this page