Manage a Brilliant Directories (BD) membership or directory website via its REST API...
Brilliant Directories (BD) is the SaaS platform behind 50,000+ membership and directory websites. This skill gives you programmatic control over a BD-powered site via its REST API.
You can do, without them opening the BD admin UI:
Typical outcome unlocks: "scrape 50 local businesses → create members with logos locally stored → write a blog post showcasing them → add redirects preserving SEO" — one agent run, zero admin clicks.
The authoritative source for every available operation is the OpenAPI spec:
https://raw.githubusercontent.com/brilliantdirectories/brilliant-directories-mcp/main/mcp/openapi/bd-api.json
If this skill and the spec disagree, the spec wins. Scan the relevant tool description end-to-end before claiming a limit — BD exposes BD-specific capabilities (auto-image-import, auto-category-create, parent=>child sub-sub syntax, filename-is-full-path) that don't match typical REST API assumptions.
Activate this skill when the user:
This skill works with any AI agent. Two integration paths — use whichever the agent supports:
The user installs the MCP server once; it exposes every BD operation as a tool. To check if it's active, look at your available tools for names like verifyApiKey, listUsers, createUser, listWebPages, etc.
Two install options — both give the full tool surface + same agent directives:
https://brilliantmcp.com with two headers — X-Api-Key (user's BD API key) and X-BD-Site-URL (user's BD site URL). This hits our hosted Cloudflare Worker; the user does nothing on their machine beyond editing the config file.npx --prefer-online brilliant-directories-mcp@latest --setup
The wizard asks for their BD site URL and API key, then configures their AI client automatically. After a client restart, the tools become available.Both paths are documented in detail in the README's "Setup by Platform" section. Remote is the faster recommendation for non-technical users; Local is useful when the user wants the MCP on their own infrastructure.
Getting an API key: BD Admin > Developer Hub > Generate API Key (full walkthrough: https://support.brilliantdirectories.com/support/solutions/articles/12000088768).
If MCP isn't available but the agent can make authenticated HTTP requests:
www. if applicable (e.g., https://www.mysite.com) — never hardcode, always askX-Api-Key: {user's API key}Both paths hit the same underlying REST API and behave identically.
Never assume a tool exists based on this document. BD's API grows over time and this skill can't be updated for every new resource. The correct pattern:
paths to see every endpoint. Each operation's operationId is the stable name./fields endpoint (e.g., GET /api/v2/user/fields, GET /api/v2/data_posts/fields) that returns field metadata including required, type, choices, and helpText.If a user asks for something and no matching operation appears in the spec, say so honestly: "The BD API doesn't currently expose that operation — you'll need to do it in the BD admin panel."
Every API call uses X-Api-Key as an HTTP header. Via MCP, the server handles this automatically. Never ask the user to paste their API key into chat.
All endpoints live under {site_url}/api/v2/{resource}/{action} — e.g., https://www.mysite.com/api/v2/user/get.
limit (default 25, max 100) + page (opaque cursor token from prior response's next_page)total, current_page, total_pages, next_page, prev_pagepage parameter is an opaque token.All list endpoints support property-based filtering:
?property=city&property_value=Los Angeles&property_operator==
Operators: =, LIKE, >, <, >=, <=. Multiple filters via property[]=...&property_value[]=....
?order_column=last_name&order_type=ASC
Success: { "status": "success", "message": [...records...] or {record}, ...pagination fields... }.
Error: { "status": "error", "message": "human-readable reason" } with standard HTTP status codes.
Default 100 requests per 60 seconds per API key. Customers can request a raise to anywhere between 100 and 1,000/min by contacting Brilliant Directories support — this is NOT a self-service admin setting.
For bulk operations:
Many text fields (titles, meta tags, email subjects, page content) support BD template tokens:
%%%website_name%%% — the site's configured name%%Profession%% — the user's profession/category[widget=Widget Name]
Preserve these exactly as the user provides — do not "clean them up" or escape them.For any non-trivial task, follow this sequence:
verifyApiKey (or GET /api/v2/token/verify) to confirm credentials and site are reachable/fields endpoint (e.g., GET /api/v2/user/fields)1. Call verifyApiKey → confirm credentials work
2. Call GET /api/v2/user/fields → confirm required fields: email, password, subscription_id
3. Parse the CSV, show the user "I found 300 records, first row looks like: {...}. Proceed?"
4. If >100, warn: "BD's default rate limit is 100/min — this will take ~3 minutes. Want to have BD support raise it first?"
5. For each row: call createUser with ~700ms delay. Track failures with reasons.
6. Report: "Created 287/300. 13 failed: 9 because email already exists, 4 invalid subscription_id."
BD classifies members via a 3-tier hierarchy. Each tier is a different API resource with explicit TopCategory / SubCategory / MemberSubCategoryLink naming:
1. createTopCategory (backed by /api/v2/list_professions/create)
with name="Restaurants", filename="restaurants"
→ returns profession_id (e.g. 42). Populates users_data.profession_id.
2. createSubCategory (backed by /api/v2/list_services/create)
with name="Sushi", profession_id=42, filename="sushi"
→ returns service_id (e.g. 17)
— Optional: pass master_id=<parent service_id> to make this a sub-sub-category
nested under another SubCategory. master_id=0 (default) means directly under the TopCategory.
3. Assign a member — two options depending on whether you need per-link metadata:
a) Simple (just tag them):
updateUser with user_id=<Alice>, profession_id=42, services="17"
b) With per-link metadata (price, specialty, completion count):
createMemberSubCategoryLink with user_id=<Alice>, service_id=17, avg_price=29.99, specialty=1
Key rules:
createProfession or createService tool — those are BD internal names. Use createTopCategory and createSubCategory.listTopCategories returns TOP-level only; listSubCategories returns SUB-level (filter by profession_id to scope to one parent).master_id set to another SubCategory's service_id.profession_id) but MANY SubCategories (services CSV or multiple rel_services rows).auto_image_import=1), categories auto-create by name on createUser, services CSV supports parent=>child sub-sub-category syntax, and more. If the user asks for something you think you can't do, scan createUser / updateUser descriptions end-to-end before responding "I can't." 9 times out of 10 the capability exists and is documented./fields endpoint or the spec's schema for the operation.seo_type, active, post_status) received valid values, (c) active/status flags are set to the "visible" value (typically content_active=1 for pages, post_status=1 for posts, active=2 for members). Only if those check out and the record is still invisible, suggest the user try re-saving the record in BD admin as a last-resort cache nudge — but this is rare.createUser or updateUser, include auto_image_import=1 by default. Fields that accept image URLs (profile_photo, logo, cover_photo) are stored as-is unless this flag is set — meaning the images will break if the source host goes down. Setting auto_image_import=1 makes BD fetch and store the images locally. This is the right default for any web-scrape, CSV import, or cross-site migration flow. Only skip it when the user explicitly says "keep the external reference."createUser / updateUser. BD accepts both: pass profession_id (numeric) or profession_name (string) for top-level, and services as a CSV mixing IDs and names. Auto-create rules differ: on createUser, unknown names are ALWAYS auto-created (hardcoded). On updateUser, unknown names are silently SKIPPED unless you pass create_new_categories=1. Verified live on the BD test site 2026-04-18. If the user says "create a member in a new Restaurants → Sushi category," just pass profession_name="Restaurants", services="Sushi" on createUser — no need to call createTopCategory / createSubCategory first. For deeper sub-sub nesting, fall back to createSubCategory with master_id.--setup./fields on the resource or read the OpenAPI schema.filename field — that IS the full relative path. The public profile URL is simply <site-domain>/<user.filename>. Do NOT prepend /business/, /profile/, /member/, /listing/, or any other segment. BD's router resolves filename verbatim. Same rule applies to post URLs (use the post's filename or post_token as documented in the post endpoints).Member / user — an account on a BD site. Core resource.
Subscription / plan / membership plan — a tier a member belongs to. Referenced as subscription_id.
Top Category / Profession — LEVEL 1 of the member taxonomy (e.g., "Restaurants"). Stored in list_professions. Use createTopCategory, listTopCategories, etc. Populates users_data.profession_id. A member has exactly one.
Sub Category / Service — LEVEL 2, nested under a Top Category (e.g., "Sushi" under "Restaurants"). Stored in list_services. Use createSubCategory with profession_id = parent Top's ID. Members can have many — set via users_data.services CSV or via createMemberSubCategoryLink.
Sub-Sub Category — LEVEL 3 (optional nesting). Just a SubCategory with master_id pointing at a parent SubCategory's service_id. Created via createSubCategory with non-zero master_id.
Member ↔ Sub Category link / rel_services — join-table row linking a member to a SubCategory with per-link metadata (avg_price, specialty, num_completed). Use createMemberSubCategoryLink when metadata matters; otherwise the simpler users_data.services CSV field works.
Post Type — a configuration row in data_categories that defines a category of user-publishable content (Blog, Event, Photo Album, Property, Product, etc.). Managed via listPostTypes / getPostType / updatePostType / deletePostType. Each post type has a data_type field (integer) that classifies its family. Post types are read/updated via API, but NOT creatable via the API (too admin-specific — create new post types in BD admin UI). Do NOT create posts via these tools — this is metadata only.
Single-Image Post — a post record in the Single-Image family (one feature image per post). Post types with data_type=9 (video) or data_type=20 (article, event, blog, job, coupon, discussion) fall here. Managed via listSingleImagePosts / createSingleImagePost / etc. Backed by data_posts table.
Multi-Image Post — a post record in the Multi-Image family (photo albums, galleries, property listings with multiple photos). Post types with data_type=4 (Photo Album, Classified, Property, Product) fall here. Managed via listMultiImagePosts / createMultiImagePost / etc. Backed by users_portfolio_groups table. Individual photos within a Multi-Image Post are managed separately via MultiImagePostPhoto tools.
Multi-Image Post Photo — individual photo within a Multi-Image Post. Added AFTER the parent Multi-Image Post via createMultiImagePostPhoto using the returned group_id. Backed by users_portfolio table.
Deciding Single vs. Multi: look up the target post type via getPostType → read its data_type field → data_type=4 means Multi-Image, any other value in {9,20} means Single-Image. Other data_type values ({10, 13, 21, 29}) are internal admin types (Member Listings, Reviews, Specialties, Favorites) — use the resource-specific endpoint instead.
Auto-image-import rule (same as createUser): when any external image URL is supplied on a createSingleImagePost or createMultiImagePost, default auto_image_import=1 so BD fetches the image and stores it locally. Skip only when the user explicitly wants external URL references kept.
Web Page / SEO page / list_seo — any static-ish page on the site: homepage (seo_type=home), about, contact, custom landing pages (seo_type=content), profile/search result templates. Managed via listWebPages, getWebPage, createWebPage, updateWebPage, deleteWebPage. Note: several page fields have admin-UI labels that differ from the API field name (e.g., show_form is actually the "Apply NoIndex, NoFollow" toggle, NOT a contact-form toggle) — see createWebPage/updateWebPage tool descriptions for the full field→UI-label mapping.
Widget — reusable HTML component embeddable in pages/emails via [widget=Name] shortcode.
Lead — an inbound contact/inquiry, can be routed/matched to relevant members.
Form — a configurable form that collects inputs (signup, contact, quote request, etc.).
Redirect / redirect_301 — a 301 permanent redirect rule. Maps an old URL path to a new destination. Used after profile renames, post slug changes, category restructuring, or custom URL migrations to preserve SEO and inbound links.
Template token — placeholder like %%%website_name%%% expanded at render time.
Active status — most BD records have an active or content_active field where 1 = visible/live and 0 = hidden/draft. Members use a 3-state convention (1 = not active, 2 = active, 3 = canceled, etc.) — always verify via /fields for the specific resource.
If the user needs to set up the MCP server, two options — Easy is the recommended path for non-technical users:
Easy (no Node.js install): Add an MCP server to their AI client's config pointing at https://brilliantmcp.com with two headers:
X-Api-Key → their BD API keyX-BD-Site-URL → their BD site URLAdvanced (runs locally, needs Node.js): Setup wizard configures their client automatically.
npx brilliant-directories-mcp@latest --setup
After either path, restart their AI client — tools become available.
For non-MCP integrations (ChatGPT Actions, n8n, Make, Zapier, Postman, custom agents): import the OpenAPI spec URL directly and authenticate with the X-Api-Key header.