Enhancely API (1.0.0)

Download OpenAPI specification:

Overview

The Enhancely API provides automatic generation and retrieval of Schema.org JSON-LD structured data for your web pages. This structured data helps search engines, AI platforms, and AI search tools better understand and represent your content.

Quick Start Guide

How It Works

Enhancely API Workflow Sequence Diagram

Get Started in 3 Steps

1. Get Your API Key - Log in to the Enhancely Dashboard, add your domain, verify ownership, and copy your API key.

2. Make Your First Request - POST your page URL to /api/v1/jsonld with your API key. First request returns 201 (queued for processing). Wait a few minutes, then request again to get 200 with your generated JSON-LD.

3. Integrate Into Your Website - Add the returned JSON-LD in a <script type="application/ld+json"> tag in your page's <head> section. Implement caching with ETags for production.

Key Benefits

  • Automatic Updates: Nightly crawls detect content changes and regenerate JSON-LD
  • Efficient Caching: ETag-based validation minimizes bandwidth and API calls
  • Always Fresh: Your structured data stays synchronized with page content
  • Minimal Maintenance: Automatic nightly updates with manual cache clearing only when you update content

Prerequisites

This API is exclusively available to Enhancely customers who have:

  1. Added their domain to the Enhancely platform
  2. Validated domain ownership
  3. Retrieved their domain-specific API key

Integration Approaches

POST vs GET: Which Endpoint to Use

Use POST /api/v1/jsonld for CMS & Website Integration:

  • Primary endpoint for page-level integration
  • Automatically creates records if they don't exist
  • Supports sending complex URLs in request body (no query string length limits)
  • Returns 412 Precondition Failed when ETag matches (cache valid)
  • Ideal for server-side rendering in templates

Use GET /api/v1/jsonld/{hash} for:

  • Polling processing status after receiving 201/202 from POST
  • Direct retrieval when you already have the MD5 hash
  • Returns 304 Not Modified when ETag matches (cache valid)

Use GET /api/v1/jsonld for:

  • Listing all JSON-LD records for your domain
  • Monitoring and troubleshooting with filters

For integrating Enhancely into your website or CMS, follow this pattern:

  1. Template Integration: Add the API call in your page template's <head> section
  2. URL Normalization: Strip query parameters, hashes, and trailing slashes before caching
  3. Cache-First Strategy: Check local cache before making API requests (recommended TTL: 1 week)
  4. Cache Key Generation: Use MD5 hash of the normalized URL as the cache key
  5. ETag Validation: Always send If-None-Match header with cached ETag
  6. Silent Degradation: Return empty output on errors to avoid breaking page rendering
  7. Cache Invalidation: Clear local cache when you manually update page content via CMS (use CMS hooks like page.update:before). Auto-clear cache in local/development environments for testing.

Note: Enhancely automatically checks all indexed URLs nightly. Normal content changes are detected via ETag validation on your next API call—manual cache clearing is only needed when you actively update content through your CMS.

Cache Strategy

Enhancely uses HTTP ETag-based caching:

HTTP-Level Caching (ETags)

Every JSON-LD response includes an ETag header—a unique identifier for that version of the content. Use ETags for efficient caching:

# First request
POST /api/v1/jsonld
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Accept: application/json

{"url": "https://example.com/page"}

HTTP/1.1 200 OK
ETag: "a1b2c3d4e5f6"
Content-Type: application/json

{
  "hash": "7c165c13f93d7ca168bcfbd73cf563e3",
  "url": "https://example.com/page",
  "jsonld": {...},
  "metadata": {},
  "etag": "a1b2c3d4e5f6",
  "crawled_at": "2025-01-16T14:30:00Z",
  "status": "ready"
}
# Subsequent request with cached ETag
POST /api/v1/jsonld
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Accept: application/json
If-None-Match: "a1b2c3d4e5f6"

{"url": "https://example.com/page"}

HTTP/1.1 412 Precondition Failed

Benefits:

  • 412 Precondition Failed responses include minimal Problem body indicating cache is valid
  • Avoids redundant processing when content hasn't changed
  • Standard HTTP caching mechanism supported by all HTTP clients
  • Learn more: MDN: HTTP Conditional Requests

Content Change Detection

When HTML content changes, Enhancely reprocesses the JSON-LD and generates a new ETag.

  1. Check local cache for ETag and JSON-LD data
  2. Make POST request with If-None-Match header containing cached ETag
  3. Handle 412 response by returning cached data (ETag still valid)
  4. Handle 200 response by caching new ETag and JSON-LD with 1-week TTL
  5. Handle errors by returning cached data or empty output (silent degradation)

Processing Model

JSON-LD generation is asynchronous. When you submit a URL:

  1. 201 Created: The URL is queued for processing (first time submission)
  2. 202 Accepted: The URL exists but is currently being processed
  3. 200 OK: The JSON-LD already exists and is available (with current status)

Processing typically takes 1-3 minutes depending on page complexity and queue depth. The response includes a status field:

  • created: Queued for processing, JSON-LD generation hasn't started yet (typically returns 201 on first POST)
  • updating: Currently being processed (returns 202 when still processing)
  • ready: JSON-LD is available and ready to use (returns 200 with full content)
  • failed: Generation failed (e.g., invalid page, unreachable URL)

For newly created records or records being processed (201/202 responses), poll the GET /api/v1/jsonld/{hash} endpoint to check when processing completes and the status becomes ready.

Rate Limiting

All endpoints are rate-limited per domain. Each response includes rate limit headers to help you track your usage.

Rate Limit Headers

RateLimit-Limit: 100        # Maximum requests allowed in the current window
RateLimit-Remaining: 75     # Requests remaining in the current window
RateLimit-Reset: 1640000000 # Unix timestamp when the limit resets

Handling Rate Limits

429 Too Many Requests Response:

{
  "type": "https://enhancely.ai/problems/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded your rate limit. Please try again later."
}

Best Practices for Rate Limit Management

1. Monitor Rate Limit Headers

Check RateLimit-Remaining and RateLimit-Reset headers to track usage and implement proactive backoff when limits are approaching.

2. Implement Retry Logic

For 429 responses, wait until the RateLimit-Reset timestamp before retrying. For 5xx server errors, use exponential backoff (e.g., 1s, 2s, 4s).

3. Use Silent Degradation

When rate limited or encountering errors, return cached data or empty output rather than breaking page rendering.

Error Handling

The API uses standard HTTP status codes and RFC 7807 Problem Details format for errors.

Key Status Codes

Success States:

  • 200 OK - JSON-LD ready and returned
  • 201 Created - URL queued for first-time processing
  • 202 Accepted - Processing in progress

Cache States:

  • 304 Not Modified (GET) / 412 Precondition Failed (POST) - Use cached data

Client Errors (4xx):

  • 400 - Invalid URL or malformed request
  • 401 - Missing/invalid API key
  • 404 - Resource doesn't exist
  • 415 - Wrong Content-Type header
  • 429 - Rate limit exceeded

Server Errors (5xx):

  • 500/502/503 - Retry with exponential backoff, use cached data

Error Response Format

{
  "type": "https://enhancely.ai/problems/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded your rate limit. Please try again later."
}

Best Practices

  • Silent Degradation: Return cached data or empty output on errors—never break page rendering
  • Cache on Success: Only cache 200 responses with ETag
  • Use Cache on 412/5xx/429: Return cached data when receiving these status codes
  • Don't Retry Client Errors: Log and return empty for 400/401/404
  • Monitor in Production: Use tools like Sentry or New Relic

JSON-LD Endpoints

Endpoints for generating and retrieving Schema.org JSON-LD structured data from web page URLs.

These endpoints enable automatic creation of rich structured data that helps search engines, AI platforms, and AI search tools better understand and represent your content.

List all JSON-LD records for your domain

Retrieves a list of all JSON-LD records associated with your domain, providing an overview of indexed URLs and their processing status.

Primary use cases: Monitoring, troubleshooting, and auditing. For website integration, use the POST endpoint instead.

Filtering: Supports filtering by status, hash, etag, url, and timestamps (created_at, updated_at, crawled_at).

Authorizations:
BearerAuth
query Parameters
etag
string
Example: etag=a1b2c3d4e5f6

Filter by ETag value. Use * to match any record with an ETag, or provide a specific ETag value.

hash
string^[a-f0-9]{32}$
Example: hash=7c165c13f93d7ca168bcfbd73cf563e3

Filter by MD5 hash of the URL. See GET /api/v1/jsonld/{hash} endpoint for hash calculation details.

url
string <uri>
Example: url=https://example.com/page

Filter by the source URL.

id
string

Filter by JSON-LD @id field.

status
string (JsonLdStatus)
Enum: "created" "updating" "failed" "ready"
Example: status=ready

Filter by processing status.

created_at
string <date-time>
Example: created_at=2025-01-01T00:00:00Z

Filter records created after this timestamp.

updated_at
string <date-time>
Example: updated_at=2025-01-01T00:00:00Z

Filter records updated after this timestamp.

crawled_at
string <date-time>
Example: crawled_at=2025-01-01T00:00:00Z

Filter records crawled after this timestamp.

Responses

Response samples

Content type
application/json
[
  • {
    • "hash": "7c165c13f93d7ca168bcfbd73cf563e3",
    • "etag": "a1b2c3d4e5f6",
    • "crawled_at": "2025-01-16T14:30:00Z",
    • "status": "ready"
    },
  • {
    • "hash": "9d8c7b6a5e4f3d2c1b0a9e8d7c6b5a4f",
    • "etag": "f6e5d4c3b2a1",
    • "crawled_at": "2025-01-16T15:00:00Z",
    • "status": "ready"
    },
  • {}
]

Generate or retrieve JSON-LD for a URL (Primary Integration Endpoint)

Recommended endpoint for CMS plugins and website integrations.

Submits a URL for JSON-LD generation or retrieves existing data if already processed. Automatically creates new records if they don't exist.

Response Codes:

  • 200 OK - JSON-LD exists (check status: ready, updating, or failed)
  • 201 Created - URL queued for first-time processing (poll GET /{hash} for completion)
  • 202 Accepted - Currently being processed (poll GET /{hash} for completion)
  • 412 Precondition Failed - ETag matches, use cached data

Key Features:

  • Asynchronous processing (typically a few minutes for new URLs)
  • ETag-based conditional requests for efficient caching
  • Supports complex URLs in request body (no query string limits)
Authorizations:
BearerAuth
header Parameters
If-None-Match
string
Example: a1b2c3d4e5f6

Optional. The ETag value from a previous response. If provided and matches the current ETag, returns 412 Precondition Failed.

Accept
string
Enum: "application/json" "application/ld+json"
Example: application/json

Optional. Specify application/ld+json to receive only the JSON-LD content without wrapper metadata. Defaults to application/json which includes metadata fields (status, etag, hash, etc.).

Request Body schema: application/json
required

Required. JSON request body with the URL to generate JSON-LD for. The Content-Type header must be application/json.

url
required
string <uri>

The target page URL to generate JSON-LD for. Example: https://example.com/blog/automatic-jsonld-with-enhancely.

Responses

Request samples

Content type
application/json

Response samples

Content type
{}

Retrieve a specific JSON-LD document by URL hash

Retrieves JSON-LD for a URL using its MD5 hash. Primarily used for polling processing status after POST returns 201/202.

Primary use cases:

  • Polling processing status after POST returns 201/202
  • Direct retrieval when you have the MD5 hash
  • ETag-based caching (returns 304 when content unchanged)

URL Hash Calculation:

The hash parameter is the MD5 hash of the absolute URL (lowercase hexadecimal):

import crypto from 'crypto';
const hash = crypto.createHash('md5').update('https://example.com/page').digest('hex');
// Result: "7c165c13f93d7ca168bcfbd73cf563e3"

Response Codes:

  • 200 OK - JSON-LD returned with metadata (includes status field)
  • 304 Not Modified - Content unchanged (when If-None-Match header matches ETag)
  • 404 Not Found - Hash doesn't exist (use POST to create)
Authorizations:
BearerAuth
path Parameters
hash
required
string^[a-f0-9]{32}$

MD5 of the absolute URL (32 lowercase hexadecimal characters). Example: 7c165c13f93d7ca168bcfbd73cf563e3.

header Parameters
If-None-Match
string
Example: a1b2c3d4e5f6

Optional. Return 304 Not Modified if the supplied ETag matches the current resource ETag.

Accept
string
Enum: "application/json" "application/ld+json"
Example: application/json

Optional. Specify application/ld+json to receive only the JSON-LD content without wrapper metadata. Defaults to application/json which includes metadata fields (status, etag, hash, etc.).

Responses

Response samples

Content type
{}