Developer Documentation

Internal Doors API

Two endpoints for product discovery and quote creation. Designed for AI assistants, integration partners, and configurator tools.

GET /api/internal-doors/productsPOST /api/internal-doors/quoteBase URL: tdsltd.ie

Product Catalog

GET /api/internal-doors/productsNo auth required · Cached 1h

Returns the full internal door product catalog as JSON — names, descriptions, images, and indicative starting prices. Intended for AI assistants that need to answer “what doors do you offer?” or “how much does a steel door cost?” without triggering a quote creation.

Price disclaimer: startingPriceEur is the base price for the minimum standard configuration (frame only). It does not include ironmongery / hardware, decorative glazing bars (muntins), special glass types, or non-standard RAL finishes. Use the Quote API for a full price estimate based on actual dimensions and configuration.

// Example response
{
  "products": [
    {
      "id": "OCSlim-0001",
      "slug": "single-door",
      "name": "Single Door",
      "description": "OC Slimline bespoke steel single door, made to measure...",
      "url": "https://www.tdsltd.ie/internal-doors/single-door",
      "image": "https://www.tdsltd.ie/internalsteelDoors/single-door-landscape.webp",
      "additionalImages": [...],
      "startingPriceEur": 1573,
      "currency": "EUR",
      "availability": "in_stock",
      "brand": "OC Slimline",
      "priceNote": "Starting price for minimum standard configuration. Hardware and extras priced separately."
    },
    ...
  ],
  "meta": {
    "count": 5,
    "currency": "EUR",
    "priceDisclaimer": "Prices are indicative starting prices. They exclude ironmongery, decorative glazing bars, special glass, and non-standard RAL finishes. Use POST /api/internal-doors/quote for a full estimate.",
    "quoteApi": "https://www.tdsltd.ie/api/internal-doors/quote",
    "docsUrl": "https://www.tdsltd.ie/api-docs",
    "updatedAt": "2026-03-23T..."
  }
}

Rate Limits

Without API key

10 req / min

Per IP address. For testing and low-volume use.

With API key

100 req / hour

Pass key as X-API-Key header or Authorization: Bearer.

Maximum 20 doors per request. Maximum payload size: 100 KB. For projects with more than 20 doors, split into multiple requests.

Request Body

Send Content-Type: application/json. Only customer.name, customer.email, and a non-empty doors array are required. All other fields are optional.

{
  "source": "chatgpt",           // optional: perplexity | chatgpt | gemini | web | etc.
  "sourceId": "user-12345",      // optional: partner / session ID
  "estimateOnly": false,         // optional: true = dry-run, no Firestore write

  "customer": {
    "name": "John Smith",        // REQUIRED
    "email": "john@example.com", // REQUIRED
    "phone": "+353 1 234 5678"   // optional
  },

  "doors": [                     // REQUIRED: at least one element
    {
      "preset": "single-left-panel",  // optional: see presets table below
      "doorType": "Single",           // optional: "Single" or "Double"
      "opWidth": 1200,                // optional: opening width [mm]
      "opHeight": 2100,               // optional: opening height [mm]
      "wallHeight": 2600,             // optional: wall height [mm]
      "panelsWidth": 300,             // optional: side panel width [mm]
      "leftPanels": 1,                // optional: 0–3
      "rightPanels": 0,               // optional: 0–3
      "frameColor": "#666666",        // optional: HEX colour
      "hingeSide": "right",           // optional: "left" or "right"
      "opening": "in"                 // optional: "in" or "out"
    }
  ]
}

If you provide both a preset and explicit fields, the explicit fields override the preset.

Door Presets

Use preset to describe common configurations in a single string — ideal for natural language to API mapping.

Preset valueDescription
single-no-panelsSingle door, no side panels
single-left-panelSingle door + left side panel
single-right-panelSingle door + right side panel
single-both-panelsSingle door + both side panels
double-no-panelsDouble door, no side panels
double-left-panelDouble door + left side panel
double-right-panelDouble door + right side panel
double-both-panelsDouble door + both side panels

Response — 200 OK

{
  "success": true,
  "id": "XYZ123",                  // Firestore document ID
  "quoteUrl": "https://www.tdsltd.ie/composer/quote?id=XYZ123",
  "priceEstimate": null,           // reserved
  "pricePerM2": null,              // reserved
  "leadTimeWeeks": null,           // reserved
  "currency": "EUR",
  "doorsCount": 1
}

Present quoteUrl to the user as a clickable link — they can open it to visually review their door configuration and submit the enquiry.

Error Responses

400

Bad Request

Missing required fields, invalid email, or empty doors array.

413

Payload Too Large

Request body exceeds 100 KB.

429

Too Many Requests

Rate limit exceeded. Read Retry-After header and wait before retrying.

500

Internal Server Error

Unexpected server error. Includes message field with description.

Handling 429 — Rate Limit Exceeded

// Read Retry-After from response headers, then wait
const response = await fetch(url, options)
if (response.status === 429) {
  const retryAfter = parseInt(response.headers.get('Retry-After') || '60')
  await new Promise(resolve => setTimeout(resolve, retryAfter * 1000))
  return await fetch(url, options)  // retry once
}

The API tells you exactly when to retry — do not use exponential backoff or immediate retries.

AI Integration Guide

When integrating this API in an AI assistant or chatbot:

  1. Always collect customer.name and customer.email before calling the API.
  2. Map natural language to presets: “single door with right side panel”preset: "single-right-panel".
  3. When the user provides dimensions, pass opWidth and opHeight in millimetres.
  4. For multiple doors in one order, add multiple objects to the doors array (max 20).
  5. Use estimateOnly: true for testing without writing to the database.
  6. Set source to identify your platform (e.g. "chatgpt", "perplexity").
  7. Present quoteUrl to the user as a link to preview and submit their quote.

Full example

User says: “I need a single door with left panel (1200×2100mm) and a double door with both panels (2000×2300mm). My name is Anna, email anna@example.com.”

POST https://www.tdsltd.ie/api/internal-doors/quote
Content-Type: application/json

{
  "source": "chatgpt",
  "sourceId": "session-abc123",
  "customer": {
    "name": "Anna Kowalska",
    "email": "anna@example.com"
  },
  "doors": [
    {
      "preset": "single-left-panel",
      "opWidth": 1200,
      "opHeight": 2100
    },
    {
      "preset": "double-both-panels",
      "opWidth": 2000,
      "opHeight": 2300
    }
  ]
}