Skip to content
Back to Docs

API Reference

Read your directory's listings and reviews from any site, and send in reviews and inquiries, with the REST API. All endpoints return JSON.

Machine-readable spec: /openapi.json (OpenAPI 3.1), for API clients, code generators and AI agents.

Authentication

All API requests require an API key. Each directory has its own key: in the dashboard, open Directories, pick your directory, then go to Settings → API Key. You can copy or regenerate it there.

curl -H "Authorization: Bearer YOUR_API_KEY" \
     https://directoryduck.com/api/v1/public/listings

Include your API key in the Authorization header with every request. A missing or wrong key returns 401 with { "error": { "code": "UNAUTHORIZED", "message": "…" } }.

GET requests may pass the key as a key query parameter instead, for example /api/v1/public/listings?key=YOUR_API_KEY. Those responses are cached by our CDN (about a minute, then refreshed in the background), which is what the full-directory embed uses. POST requests always need the Authorization header.

Base URL

https://directoryduck.com

All endpoint paths below are relative to this base URL, for example https://directoryduck.com/api/v1/public/listings.

Endpoints

GET/api/v1/public/directory

Get the directory that owns your API key: its name, slug, and description, and what the full-directory embed shows (branding is false only for a Pro directory that hid "Powered by DirectoryDuck").

Response

{
  "data": {
    "id": "8f2c…",
    "name": "Chicago Restaurants",
    "slug": "chicago-restaurants",
    "description": "Best restaurants in Chicago",
    "embed": { "fullEmbed": true, "branding": true }
  }
}
GET/api/v1/public/listings

Get the published listings in your directory with pagination: featured listings first (featured: true, Starter and up, until the date you set), then the rest, each sorted by name.

Query Parameters

  • page page number, default 1
  • pageSize results per page, default 20, max 100
  • search matches name or description
  • category listings tagged with this category

Response

{
  "data": [
    {
      "id": "3b9a…",
      "name": "Joe's Pizza",
      "slug": "joes-pizza",
      "description": "…",
      "email": "hello@joespizza.example",
      "websiteUrl": "https://joespizza.example",
      "logoUrl": null,
      "isVerified": true,
      "categories": ["pizza"],
      "location": {
        "street_address": "123 Main St",
        "city": "Austin",
        "state": "TX",
        "postal_code": "78701",
        "country": "US"
      },
      "reviewCount": 42,
      "averageRating": 4.8,
      "createdAt": "2026-10-01T12:00:00Z",
      "featured": true
    }
  ],
  "meta": { "total": 150, "page": 1, "pageSize": 20 }
}
GET/api/v1/public/listings/:slug

Get a single listing by its slug, with its review count and average rating.

Response

{
  "data": {
    "id": "3b9a…",
    "name": "Joe's Pizza",
    "slug": "joes-pizza",
    "description": "…",
    "email": "hello@joespizza.example",
    "websiteUrl": "https://joespizza.example",
    "logoUrl": null,
    "isVerified": true,
    "verifiedAt": "2026-10-02T09:30:00Z",
    "categories": ["pizza"],
    "location": {
      "street_address": "123 Main St",
      "city": "Austin",
      "state": "TX",
      "postal_code": "78701",
      "country": "US"
    },
    "createdAt": "2026-10-01T12:00:00Z",
    "updatedAt": "2026-10-05T08:00:00Z",
    "featured": true,
    "stats": { "reviewCount": 42, "averageRating": 4.8 }
  }
}
GET/api/v1/public/reviews

Get the approved reviews for one listing, newest first. Pass either listing or listingId.

Query Parameters

  • listing listing slug
  • listingId listing id
  • page page number, default 1
  • limit results per page, default 10, max 50

Response

{
  "data": [
    {
      "id": "c41d…",
      "reviewerName": "John D.",
      "reviewerCompany": null,
      "reviewerTitle": null,
      "rating": 5,
      "title": "Best pizza in town",
      "body": "Thin crust, fast service, friendly staff.",
      "pros": null,
      "cons": null,
      "isVerified": false,
      "createdAt": "2026-10-03T18:20:00Z",
      "response": null
    }
  ],
  "meta": { "total": 42, "page": 1, "pageSize": 10 }
}
POST/api/v1/public/reviews

Submit a review for a published listing. It stays pending until you approve it in the dashboard. pros and cons are optional.

Request Body

{
  "listing": "joes-pizza",
  "reviewerName": "John D.",
  "reviewerEmail": "john@example.com",
  "rating": 5,
  "title": "Best pizza in town",
  "body": "Thin crust, fast service, friendly staff.",
  "pros": "Fast service",
  "cons": "Small dining room"
}

Response

{
  "data": {
    "id": "c41d…",
    "message": "Review submitted successfully. It will be visible after moderation.",
    "createdAt": "2026-10-11T15:00:00Z"
  }
}
POST/api/v1/public/inquiries

Submit an inquiry to your directory, optionally about one listing. It lands in the Inquiries tab of your directory. listing, company, phone, and subject are optional; listing links the inquiry only if that listing is published (status Active), otherwise the inquiry arrives unlinked.

Request Body

{
  "name": "Jane Smith",
  "email": "jane@example.com",
  "message": "I'd like to book a table for six on Friday.",
  "listing": "joes-pizza",
  "company": "Acme Co",
  "phone": "+1 555 0100",
  "subject": "Group booking"
}

Response

{
  "data": {
    "id": "9e7f…",
    "message": "Inquiry submitted successfully. We will be in touch soon.",
    "createdAt": "2026-10-11T15:00:00Z"
  }
}

Rate Limits

GET requests

100

per minute, per directory API key

POST requests

50

per minute, per directory API key

These limits are the same on every plan today. GET requests authenticated with the key query parameter are cached by our CDN for about a minute, and a cached answer does not count against the limit.

Rate-limited responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Over the limit, you get a 429 with a Retry-After header.

Code Examples

JavaScript / TypeScript

const response = await fetch(
  'https://directoryduck.com/api/v1/public/listings?page=1&pageSize=20',
  {
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
    },
  }
);

const { data: listings, meta } = await response.json();
console.log(listings, meta.total);

cURL

curl -X GET \
  'https://directoryduck.com/api/v1/public/listings?page=1&pageSize=20' \
  -H 'Authorization: Bearer YOUR_API_KEY'

Need Help?

Having trouble with the API? Our team is here to help.