# Prepare & launch advertising
Campaign preparation is asynchronous. Delivery starts only after the existing business checks pass.
URL: https://benjiads.com/docs/advertising
## Before creating a campaign [#before-creating-a-campaign]
1. Read `get_workspace` and `get_workspace_requirements`.
2. Check `get_subscription` and the balance returned by `list_campaigns`.
3. Prepare and select owned creatives in the dashboard.
4. Obtain the user's authorization for the total daily budget and intended locations.
The initial public API manages the existing managed-advertising flow. A catalog flag for Google Search does not expose a Google Ads deployment endpoint. Connecting an agent does not grant access to Facebook pages or advertising accounts.
## Create in pause [#create-in-pause]
`create_campaign` (`POST /v1/campaigns`) validates the existing subscription, creative ownership, license, and funding rules, then queues preparation with **launch disabled**.
Send the selected creative IDs and the total `dailyBudgetCents` according to the [request schema](https://benjiads.com/docs/api/create-campaign). Use a unique `Idempotency-Key` for that intended campaign and reuse it for retries.
The response is `202` with a job. The durable job performs preparation and stores checkpoints so a transient provider failure can resume.
## Monitor the job [#monitor-the-job]
```bash
curl https://api.benjiads.com/v1/jobs/JOB_UUID \
-H "Authorization: Bearer $BENJIADS_API_KEY"
```
| Status | Meaning |
| ----------- | -------------------------------------------------------------------- |
| `queued` | Waiting for execution |
| `running` | Preparing or resuming the campaign |
| `ready` | Prepared; delivery has not been activated by this job |
| `live` | The job activated delivery |
| `failed` | Needs attention; provider objects may already exist |
| `cancelled` | Execution stopped; this does not prove provider objects were removed |
`hold: "license"` indicates a pack prepared under a license hold. Follow the dashboard verification and redeployment flow.
## Launch explicitly [#launch-explicitly]
Inspect the prepared campaign, confirm the saved budget with the user, and call `launch_campaign` with its campaign ID and a new action key.
Activation checks the subscription, billing pause, available funding, current license requirements, and preparation state. Location packs must be complete. An initial onboarding pack additionally needs the existing verified payment authorization.
The daily budget is the **total across locations**. For example, a $30/day budget across three equal locations is $10/day each, subject to the existing minimum budget validation. Adding locations does not turn it into $90/day.
## Pause and measure [#pause-and-measure]
`pause_campaign` pauses the selected campaign using the existing access rules. `list_campaigns` returns saved campaign state and spend. `get_metrics` returns site/lead performance, and `list_leads` preserves subscription-based masking.
The initial v1 does not expose creative generation, domain purchases, wallet top-ups, campaign deletion, or arbitrary provider operations. The dashboard remains available for those supported product actions.
# API reference
The live request and response contracts, generated from the same schemas used by REST and MCP.
URL: https://benjiads.com/docs/api
## Base URL [#base-url]
```text
https://api.benjiads.com/v1
```
Choose an operation in the sidebar to inspect its parameters, request body, response schema, and generated code examples. The interactive request panel sends only when you explicitly use its send control.
[Download OpenAPI](https://api.benjiads.com/v1/openapi.json) to generate a client in your preferred language. Each operation's `operationId` is also its MCP tool name.
## Discovery and requirements [#discovery-and-requirements]
* [List supported verticals](https://benjiads.com/docs/api/list-verticals)
* [Read a vertical](https://benjiads.com/docs/api/get-vertical)
* [Read the connected workspace](https://benjiads.com/docs/api/get-workspace)
* [Check workspace license requirements](https://benjiads.com/docs/api/get-workspace-requirements)
## Sites and leads [#sites-and-leads]
* [Read the site](https://benjiads.com/docs/api/get-site)
* [Update settings](https://benjiads.com/docs/api/update-site)
* [Save a draft](https://benjiads.com/docs/api/save-site-draft)
* [Publish](https://benjiads.com/docs/api/publish-site)
* [Read leads](https://benjiads.com/docs/api/list-leads)
## Advertising [#advertising]
* [Campaigns and balance](https://benjiads.com/docs/api/list-campaigns)
* [Prepare a campaign](https://benjiads.com/docs/api/create-campaign)
* [Read a job](https://benjiads.com/docs/api/get-job)
* [Launch](https://benjiads.com/docs/api/launch-campaign)
* [Pause](https://benjiads.com/docs/api/pause-campaign)
## Billing and reporting [#billing-and-reporting]
* [Subscription](https://benjiads.com/docs/api/get-subscription)
* [Checkout handoff](https://benjiads.com/docs/api/start-subscription)
* [Invoices](https://benjiads.com/docs/api/list-invoices)
* [Performance](https://benjiads.com/docs/api/get-metrics)
* [Integration usage](https://benjiads.com/docs/api/get-usage)
# Authentication
Use a workspace API key for your server or delegated OAuth for an agent connection.
URL: https://benjiads.com/docs/authentication
## API keys [#api-keys]
Create a key in [Integrations](/app/integrations). Select the workspace and only the permissions your integration needs. The dashboard issues keys for 90 days and displays the secret once.
```http
Authorization: Bearer bja_key_your_key
```
Keep credentials in a server secret store or the agent client's credential manager. Send them in the Authorization header. Revoke a key or agent connection in Integrations when it should stop working.
## Scopes [#scopes]
| Scope | Access |
| --------------- | -------------------------------------------------------------- |
| `site:read` | Workspace, site, vertical catalog, and license requirements |
| `site:write` | Site settings, drafts, and publication |
| `ads:read` | Campaigns, advertising balance, and preparation jobs |
| `ads:write` | Campaign preparation, launch, and pause |
| `leads:read` | Leads, with the existing subscription contact masking |
| `metrics:read` | Business performance and integration usage |
| `billing:read` | Subscription status and invoices |
| `billing:write` | Browser handoff to subscription checkout or billing management |
A write scope does not replace a read scope. For example, an agent that prepares and monitors campaigns needs both `ads:write` and `ads:read`.
## OAuth for agent clients [#oauth-for-agent-clients]
The authorization server supports public clients, dynamic registration, authorization code with **PKCE S256**, explicit workspace consent, and resource indicators.
| Endpoint | Purpose |
| ------------------------------------------- | --------------------------------------------------- |
| `/.well-known/oauth-authorization-server` | Authorization server metadata |
| `/.well-known/oauth-protected-resource/mcp` | MCP resource metadata |
| `/.well-known/oauth-protected-resource/v1` | REST resource metadata |
| `POST /oauth/register` | Register HTTPS callbacks or HTTP loopback callbacks |
| `GET /oauth/authorize` | Start the owner consent flow |
| `POST /oauth/token` | Exchange a code or rotate a refresh token |
| `POST /oauth/revoke` | Revoke the connection |
All paths above are relative to `https://api.benjiads.com`.
The owner signs in, sees the requesting app and callback origin, chooses a workspace, and approves the requested permissions. Authorization codes are single-use and expire after one minute once approved.
Use the exact resource in authorization and token requests:
* REST: `https://api.benjiads.com/v1`
* MCP: `https://api.benjiads.com/mcp`
An OAuth token issued for one resource cannot be used on the other. Personal API keys can use both interfaces.
## Refresh and revocation [#refresh-and-revocation]
Access tokens last one hour. Refresh tokens rotate on every refresh and expire at the end of the original 30-day connection lifetime. Store each new refresh token before discarding the previous one. Reusing an old refresh token revokes the connection.
An expired, revoked, or invalid credential returns `401`. Missing permissions return `403` with an OAuth challenge identifying the needed scope.
# Subscription, budget & usage
Keep the workspace subscription, advertising funds, and integration activity distinct.
URL: https://benjiads.com/docs/billing
## Three separate measurements [#three-separate-measurements]
| Measurement | What it represents | Where to read it |
| ----------------- | ----------------------------------------- | ------------------ |
| Subscription | The workspace's SaaS entitlement | `get_subscription` |
| Ad wallet | Funding available for advertising | `list_campaigns` |
| Integration usage | Admitted REST/MCP operations over 30 days | `get_usage` |
The public API introduces no additional usage price. Current subscription terms are shown in checkout; the API does not define a separate price plan.
## Subscribe through the owner flow [#subscribe-through-the-owner-flow]
```bash
curl -X POST https://api.benjiads.com/v1/billing/checkout \
-H "Authorization: Bearer $BENJIADS_API_KEY" \
-H "Idempotency-Key: subscription-handoff-001"
```
The response is a URL with `action: "complete_in_browser"`. Open it for the owner, who signs in, reviews the terms, and authorizes checkout. An existing subscriber can manage billing there.
Poll `get_subscription` afterward. Returning from the browser or receiving a checkout URL is not proof of payment. Rights come from server-verified Stripe state and signed billing events.
## Advertising money [#advertising-money]
Wallet amounts are USD cents in the BenjiAds customer-facing accounting unit.
* `balanceCents`: cumulative credited advertising funding.
* `spentLifetimeCents`: lifetime spend used by the balance calculation.
* `remainingCents`: funds currently available for advertising.
* `spentCents`: spend for the selected reporting period.
The provider-to-wallet conversion is already applied at the existing boundary. Do not add it again. If the provider is unavailable, reports can fall back to stored spend values.
Advertising funding uses the dashboard. A top-up cannot override a billing pause, a license hold, or incomplete campaign preparation. Included advertising credit is granted once per owner account.
## Failed or cancelled subscriptions [#failed-or-cancelled-subscriptions]
Existing billing rules pause delivery on failed payment or cancellation. Launch checks inspect entitlement and the billing pause separately from the wallet balance. Repair billing before retrying an activation with a new action key.
Use `list_invoices` for invoices associated with the workspace's BenjiAds subscription.
# Workspaces & products
One account can own several businesses. Each business activity has its own workspace and operating limits.
URL: https://benjiads.com/docs/concepts
## Tenant = workspace = product [#tenant--workspace--product]
In BenjiAds, **tenant**, **workspace**, and **product** refer to the same business unit. The interface calls it a workspace; some internal and API field names use `tenantId`.
For example, Alex Plumbing is one workspace with the `plumber` vertical. Alex Landscaping is another workspace with the `landscaper` vertical, even if Alex owns both.
```text
Alex's account
├── Alex Plumbing · workspace A · vertical: plumber
│ ├── Website and lead-capture funnel
│ ├── Leads and performance
│ ├── Subscription and advertising wallet
│ └── Campaigns, creatives, locations, and connections
└── Alex Landscaping · workspace B · vertical: landscaper
└── Its own site, leads, subscription, wallet, and connections
```
## What belongs to what? [#what-belongs-to-what]
| Concept | Meaning | Example |
| ---------------------------- | ------------------------------------------- | ----------------------------------------------- |
| Account | The signed-in owner | Alex |
| Workspace / tenant / product | One business activity operated in BenjiAds | Alex Plumbing |
| Vertical | The trade template and its configured rules | `plumber` |
| Location / service area | Where this business works | Austin, TX |
| Site | The workspace's public website and funnel | `alex-plumbing.benjiads.com` |
| Campaign | Advertising prepared for that workspace | A plumbing campaign targeting its service areas |
| API key / OAuth connection | Access to exactly one workspace | A reporting assistant for Alex Plumbing |
A vertical is a template, not a shared customer account. Two plumbers have separate workspaces. Their sites, leads, billing, and advertising funds stay separate.
## Multiple locations [#multiple-locations]
A workspace can have multiple locations or service areas for the **same business activity**. A location is not automatically a new workspace. For location ad packs, the daily budget is divided across the selected locations; it is not multiplied by their count.
State-specific requirements are evaluated from the workspace's selected locations. Read [licenses and restrictions](https://benjiads.com/docs/licenses) before targeting more than one state.
## Ownership and authorization [#ownership-and-authorization]
Every integration connection belongs to one workspace and carries explicit permissions. Its resource IDs are resolved inside that workspace. A campaign or job ID from another workspace cannot be used to access it.
To connect a second workspace, create a second key or approve a second OAuth connection. The `x-workspace` header cannot move an integration credential to another workspace.
## Billing boundaries [#billing-boundaries]
Subscriptions and advertising wallets belong to workspaces. Advertising funds are separate from the SaaS subscription, and integration request counters are separate from both.
The existing included advertising credit is granted once per **owner account**, not once for every newly created workspace. Creating more workspaces does not reset that allowance.
# Build with BenjiAds
Connect an app or AI agent to a local business. Publish its site, manage advertising, and measure results.
URL: https://benjiads.com/docs
## Make your first request [#make-your-first-request]
### Create a workspace [#create-a-workspace]
Sign in to [BenjiAds](/app) and set up the business. A **workspace**, also called a **tenant** or **product**, represents one business activity: for example, a plumber. An account can own several workspaces.
### Create a scoped API key [#create-a-scoped-api-key]
Open [Integrations](/app/integrations), choose the workspace, and create a key with `site:read`. Save it when shown; it cannot be displayed again.
```bash
export BENJIADS_API_KEY="bja_key_your_key"
```
### Read the connected workspace [#read-the-connected-workspace]
```bash
curl https://api.benjiads.com/v1/workspace \
-H "Authorization: Bearer $BENJIADS_API_KEY"
```
The returned workspace is the one attached to your key. You cannot switch it by sending a different workspace ID.
## Choose your interface [#choose-your-interface]
| Interface | Address | Use it for |
| --------- | ---------------------------------------------------------------------- | --------------------------------------------- |
| REST API | `https://api.benjiads.com/v1` | Server integrations and workflows |
| MCP | `https://api.benjiads.com/mcp` | AI agents that operate on a workspace |
| OpenAPI | [Download the specification](https://api.benjiads.com/v1/openapi.json) | Client generation, tooling, and API discovery |
| Markdown | [All documentation](https://benjiads.com/docs-llms-full.txt) | Give the full documentation to an agent |
REST and MCP run the same operations and enforce the same workspace, subscription, license, funding, and retry checks.
## Follow the customer journey [#follow-the-customer-journey]
1. [Understand the workspace](https://benjiads.com/docs/concepts) and [check its vertical](https://benjiads.com/docs/verticals).
2. [Connect securely](https://benjiads.com/docs/authentication) or use [MCP](https://benjiads.com/docs/mcp).
3. [Edit and publish the site](https://benjiads.com/docs/sites).
4. [Complete subscription checkout](https://benjiads.com/docs/billing) and fund advertising in the dashboard.
5. [Prepare, inspect, and launch a campaign](https://benjiads.com/docs/advertising).
6. Read leads, performance, ad balance, and integration usage.
# Licenses & state restrictions
How California, Florida, Texas, and other state-specific requirements affect preparation and activation.
URL: https://benjiads.com/docs/licenses
## Start with the vertical and locations [#start-with-the-vertical-and-locations]
Requirements depend on **the trade and the selected states together**. A plumber in California and a smart-home installer in Texas do not use the same set of fields.
The [live vertical catalog](https://benjiads.com/docs/verticals) shows the complete current rule sheet. Common configured cases include:
| Trade / activity | States | Configured information |
| -------------------------------------------------------- | -------------------- | ---------------------- |
| Contractor trades such as plumbing, electrical, and HVAC | CA, FL | `licenseNumber` |
| Smart-home camera or alarm installation | TX, FL, CA | `securityLicense` |
| Tree services | MD, CT | `licenseNumber` |
| Auto repair | CA | `barRegistration` |
| Chiropractor / dentist free or discounted first visits | FL | `flFreeExamNotice` |
| Lawn chemical treatments | Applicable locations | `pesticideLicense` |
These are distinct requirements. `securityLicense`, for example, is not an alias for the contractor license-number verification endpoint.
## Check the workspace before advertising [#check-the-workspace-before-advertising]
```bash
curl https://api.benjiads.com/v1/workspace/requirements \
-H "Authorization: Bearer $BENJIADS_API_KEY"
```
MCP: `get_workspace_requirements` with `site:read`.
The response includes the workspace's vertical, selected states, applicable fields, current license blockers in `missing`, the accepted license line, disclosures, and the dashboard address for managing the business.
An empty `missing` list means the **license-number gate** has no current blocker. It does not mean billing, budget, creatives, or campaign preparation are ready.
## License-number verification [#license-number-verification]
The current validation flow normalizes the number, validates its format, and stores a status for a state.
| State | Accepted input format | Current check |
| ------------------- | ---------------------------------- | ------------------------------------------------------------------------- |
| CA — California | 5–8 digits | CSLB registry lookup; an available registry must report an active license |
| FL — Florida | 2–4 letters followed by 5–8 digits | Format check; a valid number remains `unverified` |
| TX and other states | 3–24 letters, digits, or hyphens | Generic format check; no state registry is connected in this flow |
For states without a connected registry, a format-valid `unverified` record can satisfy the existing acceptance check. It must match the selected state. If the California registry is unavailable, the existing flow accepts a format-valid number as supplied and flags it for manual review; `unverified` does not mean registry-verified.
The workspace currently stores **one license record with one state**. Do not assume that a California record covers Florida as well. Mixed-state targeting can leave requirements unmet; inspect `missing` before proceeding.
## License holds and redeployment [#license-holds-and-redeployment]
Onboarding can prepare an ad pack in pause when a license is missing or rejected. A license hold does not authorize delivery.
1. Complete license verification in the workspace's Ads screen.
2. Redeploy the held pack through that screen so the creative carries the current license information.
3. Wait for the complete pack.
4. Complete any remaining payment and funding requirements before activation.
Payment or a wallet top-up does not remove a license hold. `launch_campaign` returns `license_redeploy_required` for a held pack even if a license was supplied afterward.
## What the public API supports [#what-the-public-api-supports]
| Action | Public interface |
| -------------------------------------------- | -------------------------------- |
| Discover trade/state rules | `list_verticals`, `get_vertical` |
| Inspect current license blockers | `get_workspace_requirements` |
| Inspect a preparation hold | `get_job` |
| Submit or verify a license number | Workspace dashboard |
| Replace a pack prepared under a license hold | Workspace dashboard |
| Launch after the rules are satisfied | `launch_campaign` |
There is no public v1 license-write tool. Agents should hand the owner back to the dashboard for verification instead of claiming a license was accepted.
# Limits, retries & errors
Make retries predictable across REST and MCP without repeating side effects.
URL: https://benjiads.com/docs/limits
## Limits [#limits]
| Limit | Value |
| --------------------------------- | ---------------------- |
| Admitted operations per workspace | 120 per rolling minute |
| Writes within that total | 20 per rolling minute |
| Request body | 512 KiB |
| Completed write replay window | At least 90 days |
REST and MCP share the limits. These are operational limits, not an additional billing schedule. REST rate-limit responses include `Retry-After: 60`.
## Idempotency [#idempotency]
Every write needs a key: `Idempotency-Key` in REST or `idempotency_key` in MCP. It must contain 8–80 letters, digits, underscores, or hyphens.
The workspace, operation, key, and normalized arguments identify one intended action. An identical retry replays the saved response, even across REST and MCP or different credentials for the same workspace. Replayed REST responses include `Idempotency-Replayed: true`.
Different arguments with the same key return `idempotency_conflict`. An action still pending returns `operation_in_progress` with a receipt ID. Inspect the site or preparation job before deciding on another action; a timeout can happen after an external side effect.
Business errors are also saved for replay. After fixing a failed prerequisite, use a new key for the newly authorized attempt. Do not use a new key merely to retry an uncertain network outcome.
## Error handling [#error-handling]
| HTTP status | Meaning | Next step |
| ----------- | ------------------------------------------------------------ | ------------------------------------------- |
| `400` | Invalid arguments or missing retry key | Correct the request |
| `401` | Missing, expired, invalid, or revoked credential | Reconnect or replace the key |
| `402` | Subscription required | Complete or repair billing |
| `403` | Missing scope, wrong workspace, or disallowed browser origin | Check the connection |
| `404` | Resource not found within the workspace | Check the ID |
| `409` | State, license, funding, or retry conflict | Read the error code and resolve the blocker |
| `413` | Body too large | Reduce the payload |
| `429` | Workspace quota reached | Wait before retrying |
| `5xx` | Internal or provider failure | Inspect state before retrying a write |
MCP tool failures use `isError: true` with a structured error code. Authentication and protocol errors can occur before the tool runs.
## Usage and tracing [#usage-and-tracing]
REST responses include `X-Request-Id`; MCP operation results include `request_id`. Keep these IDs when investigating a failure.
`get_usage` counts admitted operations in the past 30 days, grouped by operation. It includes business failures; requests rejected before admission and replayed receipts do not create a new operation.
# Connect an AI agent
Let an agent use BenjiAds through the same workspace operations as the REST API.
URL: https://benjiads.com/docs/mcp
## Remote MCP server [#remote-mcp-server]
```text
https://api.benjiads.com/mcp
```
Use a client that supports remote MCP over Streamable HTTP. The endpoint supports legacy stateless clients and the 2026-07-28 request protocol. Configure the URL in the client's integrations or MCP settings, then sign in when prompted.
Clients with custom authorization headers can use a personal API key:
```json
{
"url": "https://api.benjiads.com/mcp",
"headers": {
"Authorization": "Bearer "
}
}
```
This is the connection information; the enclosing configuration format depends on your client. OAuth clients should discover the authorization server from the `WWW-Authenticate` challenge.
## Discover, then act [#discover-then-act]
Start with read permissions. For example:
> Read my workspace, identify its vertical and state requirements, then show my site and this week's advertising results.
The server lists the tools allowed by the connection's scopes. The [API reference](https://benjiads.com/docs/api) gives each REST operation's matching MCP tool name.
Useful discovery tools:
* `get_workspace`: identify the connected business.
* `list_verticals` and `get_vertical`: discover supported trades and their rules.
* `get_workspace_requirements`: inspect location-specific license blockers.
* `get_subscription`: inspect the workspace subscription.
* `list_campaigns`: read campaigns and the available advertising balance.
## Writes and user authorization [#writes-and-user-authorization]
Before publishing a site or spending on advertising, agree on the intended change and budget with the user. Each write requires an `idempotency_key`. Reuse that key when retrying the same action.
Example arguments for `publish_site`:
```json
{
"idempotency_key": "publish-reviewed-homepage-001"
}
```
`create_campaign` prepares with launch disabled. Poll `get_job` and inspect the saved campaign before calling `launch_campaign`. A site, license, subscription, or funding restriction cannot be bypassed by the agent.
## Subscriptions and owner handoffs [#subscriptions-and-owner-handoffs]
`start_subscription` returns a browser URL. The owner signs in and authorizes the recurring subscription in BenjiAds. The MCP call itself does not charge a card or activate access.
License verification, ad-wallet funding, and account permissions use the workspace dashboard. Agents must not collect card data or fabricate a license verification result.
## Muse and other directories [#muse-and-other-directories]
The MCP endpoint is a general integration. Availability in Muse depends on the platform's connector contract and review. BenjiAds does not currently claim an approved Muse listing or a recurring subscription paid entirely inside a Muse/Link conversation.
# Sites & publication
Read business details, save a draft, and publish the reviewed website.
URL: https://benjiads.com/docs/sites
## Start with an existing workspace [#start-with-an-existing-workspace]
Create the business workspace through BenjiAds onboarding. A credential then connects to that workspace's site. The initial public API does not create accounts or new workspaces.
Site editing, publication, and lead capture use the existing freemium business rules. The dashboard's onboarding checkout flow and paid-feature gates still apply where configured.
## Read and update the site [#read-and-update-the-site]
```bash
curl https://api.benjiads.com/v1/site \
-H "Authorization: Bearer $BENJIADS_API_KEY"
curl -X PATCH https://api.benjiads.com/v1/site \
-H "Authorization: Bearer $BENJIADS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: update-business-details-001" \
-d '{"displayName":"Alex Plumbing","tagline":"Local plumbing in Austin"}'
```
The site response contains its public settings, published `siteDoc`, and current `siteDraft`. Private payment and provider account identifiers are omitted.
`update_site` changes business settings. Fields such as `locations`, `links`, and `socials` replace the supplied collection; first read the existing values to preserve items you intend to keep.
## Draft, review, publish [#draft-review-publish]
Use `save_site_draft` to submit a full BenjiAds site document. Begin with the existing `siteDoc` or `siteDraft`; preserve its structure and edit the intended blocks. The shared site builder sanitizer validates the document.
Read the draft back to review it, then publish:
```bash
curl -X POST https://api.benjiads.com/v1/site/publish \
-H "Authorization: Bearer $BENJIADS_API_KEY" \
-H "Idempotency-Key: publish-reviewed-homepage-001"
```
Publishing copies the saved draft to the published document and clears the draft. It does not purchase a domain. Domain setup remains in the dashboard.
## Leads [#leads]
Public lead capture remains available without a subscription. Reading lead contacts is gated by the workspace's entitlement: `list_leads` returns `gated: true` with masked contact details when access is absent. This masking happens on the server and also applies to MCP.
# Supported verticals
Explore the live trade catalog, the information to collect, and the configured advertising rules.
URL: https://benjiads.com/docs/verticals
A vertical defines a trade's language, onboarding questions, advertising guidance, and state-specific information. Choose the vertical that matches the workspace's actual business activity.
## Live catalog [#live-catalog]
This list comes from the published BenjiAds catalog. Expand a vertical for its fields, exclusions, disclosures, and source references. State filters show verticals with a configured state-specific rule, including rules other than a license number.
34 published verticals. A published vertical may be on hold.
| Vertical | Slug | License-number states | Status |
| --- | --- | --- | --- |
| Plumbers | `plumber` | CA, FL | go |
| Electricians | `electrician` | CA, FL | go |
| HVAC companies | `hvac` | CA, FL | go |
| Appliance repair companies | `appliance-repair` | No configured license-number gate | go |
| Handymen | `handyman` | CA, FL | go |
| Painters | `painter` | CA, FL | go |
| Flooring contractors | `flooring` | CA, FL | go |
| Carpenters | `carpenter` | CA, FL | go |
| Fence and deck contractors | `fence-deck` | CA, FL | go |
| House cleaners | `house-cleaning` | No configured license-number gate | go |
| Commercial cleaners | `commercial-cleaning` | No configured license-number gate | go |
| Carpet cleaners | `carpet-cleaning` | No configured license-number gate | go |
| Pressure washing companies | `pressure-washing` | No configured license-number gate | go |
| Lawn care companies | `lawn-care` | No configured license-number gate | go |
| Landscapers | `landscaper` | CA, FL | go |
| Tree services | `tree-service` | MD, CT | go |
| Holiday light installers | `holiday-lighting` | No configured license-number gate | go |
| Snow removal companies | `snow-removal` | No configured license-number gate | go |
| Junk removal companies | `junk-removal` | No configured license-number gate | go |
| Furniture assemblers | `furniture-assembly` | No configured license-number gate | go |
| TV mounting services | `tv-mounting` | No configured license-number gate | go |
| Smart home installers | `smart-home-installer` | No configured license-number gate | go |
| Interior designers | `interior-designer` | No configured license-number gate | go |
| Laundry services | `laundry-service` | No configured license-number gate | go |
| Auto repair shops | `auto-repair` | No configured license-number gate | go |
| Auto detailers | `auto-detailing` | No configured license-number gate | go |
| Event staffing and bartending companies | `event-staffing` | No configured license-number gate | go |
| Photographers | `photographer` | No configured license-number gate | go |
| Wedding photographers | `wedding-photographer` | No configured license-number gate | go |
| Event planners | `event-planner` | No configured license-number gate | go |
| Chiropractors | `chiropractor` | No configured license-number gate | go |
| Dentists | `dentist` | No configured license-number gate | go |
| Personal trainers | `personal-trainer` | No configured license-number gate | go |
| Hair salons | `hair-salon` | No configured license-number gate | go |
Global ad-copy exclusions: `licensed`, `license`, `certified`, `guaranteed`, `guarantee`, `specialist`, `expert`, `best`, `#1`, `cheapest`, `cure`, `pain-free`, `insured`.
## Plumbers
Slug: `plumber`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Job-specific hooks: the problem the homeowner sees, the fix, the speed.
- Trust = 'Local', 'Upfront pricing', 'Real reviews' (never a count).
Trade-specific excluded terms: none configured.
### Catalog notes
State contractor licence almost everywhere; CA/FL want the number in the ad. Google LSA 'urgent' category runs background checks on technicians.
### Catalog sources
- https://support.google.com/adspolicy/answer/6020955
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
- https://www.flsenate.gov/laws/statutes/2024/489.119
## Electricians
Slug: `electrician`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Job-specific hooks: the problem the homeowner sees, the fix, the speed.
- Trust = 'Local', 'Upfront pricing', 'Real reviews' (never a count).
Trade-specific excluded terms: none configured.
### Catalog notes
State contractor licence almost everywhere; CA/FL want the number in the ad. Google LSA 'urgent' category runs background checks on technicians.
### Catalog sources
- https://support.google.com/adspolicy/answer/6020955
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
- https://www.flsenate.gov/laws/statutes/2024/489.119
## HVAC companies
Slug: `hvac`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Job-specific hooks: the problem the homeowner sees, the fix, the speed.
- Trust = 'Local', 'Upfront pricing', 'Real reviews' (never a count).
Trade-specific excluded terms: none configured.
### Catalog notes
State contractor licence almost everywhere; CA/FL want the number in the ad. Google LSA 'urgent' category runs background checks on technicians.
### Catalog sources
- https://support.google.com/adspolicy/answer/6020955
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
- https://www.flsenate.gov/laws/statutes/2024/489.119
## Appliance repair companies
Slug: `appliance-repair`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
- Name the appliance and the symptom: 'Fridge not cooling', 'Washer won't drain'.
Trade-specific excluded terms: none configured.
### Catalog notes
No state licence in general. Google's 'third-party tech support' policy names 'repair' of consumer technology: a false positive on appliances is possible, appeal if an ad is refused.
### Catalog sources
- https://support.google.com/adspolicy/answer/13527027
## Handymen
Slug: `handyman`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Small jobs, fast: mounting, drywall, doors. Never a licence claim.
Trade-specific excluded terms: licensed, contractor.
### Catalog notes
CA: an unlicensed handyman may only advertise jobs under $1,000 and must say in the ad that he is not licensed (B&P 7027.2). Never 'licensed' without a CSLB number.
### Catalog sources
- https://law.justia.com/codes/california/code-bpc/division-3/chapter-9/article-2/section-7027-2/
## Painters
Slug: `painter`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Show the finished result: the room, the floor, the fence, the yard.
Trade-specific excluded terms: none configured.
### Catalog notes
CA: contractor licence required above $1,000 and the number must be in the ad; elsewhere often no state licence, so the ad never claims one.
### Catalog sources
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
## Flooring contractors
Slug: `flooring`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Show the finished result: the room, the floor, the fence, the yard.
Trade-specific excluded terms: none configured.
### Catalog notes
CA: contractor licence required above $1,000 and the number must be in the ad; elsewhere often no state licence, so the ad never claims one.
### Catalog sources
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
## Carpenters
Slug: `carpenter`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Show the finished result: the room, the floor, the fence, the yard.
Trade-specific excluded terms: none configured.
### Catalog notes
CA: contractor licence required above $1,000 and the number must be in the ad; elsewhere often no state licence, so the ad never claims one.
### Catalog sources
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
## Fence and deck contractors
Slug: `fence-deck`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Show the finished result: the room, the floor, the fence, the yard.
Trade-specific excluded terms: none configured.
### Catalog notes
CA: contractor licence required above $1,000 and the number must be in the ad; elsewhere often no state licence, so the ad never claims one.
### Catalog sources
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
## House cleaners
Slug: `house-cleaning`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Commercial cleaners
Slug: `commercial-cleaning`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Carpet cleaners
Slug: `carpet-cleaning`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Pressure washing companies
Slug: `pressure-washing`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Lawn care companies
Slug: `lawn-care`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **Do you hold a pesticide applicator licence?** (`pesticideLicense`): Chemical treatments need a state applicator licence; without it the ads stay on mowing and cleanup. States: all applicable locations. Collected: before-ads.
### Advertising rules
- Mowing, edging, cleanup. No fertiliser, weed control or pesticide hooks unless the tenant holds an applicator licence.
Trade-specific excluded terms: fertilization, weed control, pesticide.
### Catalog notes
Fine for mowing/cleanup. Chemical treatments are licensed per state.
## Landscapers
Slug: `landscaper`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: CA, FL. Collected: before-ads.
### Advertising rules
- Show the finished result: the room, the floor, the fence, the yard.
Trade-specific excluded terms: none configured.
### Catalog notes
CA: contractor licence required above $1,000 and the number must be in the ad; elsewhere often no state licence, so the ad never claims one.
### Catalog sources
- https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=7027.1
## Tree services
Slug: `tree-service`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **State license number** (`licenseNumber`): Required before advertising in the configured states. Benjiads checks the saved license against each selected state; missing or rejected licenses block activation. States: MD, CT. Collected: before-ads.
### Advertising rules
- Trimming, removal, storm cleanup.
Trade-specific excluded terms: none configured.
### Catalog notes
Maryland and Connecticut forbid advertising tree work without a state licence.
### Catalog sources
- https://dnr.maryland.gov/forests/pages/programapps/newtreeexpert.aspx
- https://portal.ct.gov/DEEP/Pesticides/Arborist/Commercial-Arborist-License
## Holiday light installers
Slug: `holiday-lighting`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Snow removal companies
Slug: `snow-removal`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Junk removal companies
Slug: `junk-removal`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Furniture assemblers
Slug: `furniture-assembly`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## TV mounting services
Slug: `tv-mounting`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Smart home installers
Slug: `smart-home-installer`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **Do you hold a security or low-voltage licence?** (`securityLicense`): TX (DPS), FL (alarm/low-voltage) and CA (C-7 + ACO) license camera and alarm installs; without it the ads skip cameras and alarms there. States: TX, FL, CA. Collected: before-ads.
### Advertising rules
- Smart thermostats, lighting, doorbells. Cameras and alarms only where the tenant is licensed for security work.
Trade-specific excluded terms: alarm, security system.
### Catalog notes
Google's tech-support policy lists 'installations': a Search refusal is possible, appeal. Meta: no restriction.
### Catalog sources
- https://support.google.com/adspolicy/answer/13527027
## Interior designers
Slug: `interior-designer`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
### Advertising rules
Trade-specific excluded terms: registered interior designer.
### Catalog notes
The title 'registered interior designer' is protected in some states: say 'interior designer'. Google LSA only in CA/FL.
## Laundry services
Slug: `laundry-service`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Auto repair shops
Slug: `auto-repair`. Location model: office.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
- **Your Bureau of Automotive Repair registration (business name and address as registered)** (`barRegistration`): CA ads must show the shop name and address exactly as registered with the Bureau of Automotive Repair (16 CCR 3371). States: CA. Collected: before-ads.
### Advertising rules
- Symptom-led: 'Check engine light on', 'Brakes squealing'.
Trade-specific excluded terms: none configured.
### Catalog notes
California requires the registered name and address in the ad.
### Catalog sources
- https://www.law.cornell.edu/regulations/california/16-CCR-3371
## Auto detailers
Slug: `auto-detailing`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer same-day service?** (`sameDayAvailable`): The ads may say 'same-day' only if it is true. States: all applicable locations. Collected: onboarding.
- **Do you offer free estimates?** (`freeEstimates`): The ads may say 'Free estimates' only if the landing page says it too. States: all applicable locations. Collected: onboarding.
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Event staffing and bartending companies
Slug: `event-staffing`. Location model: area.
Configured platform guidance: {"googleSearch":true,"ageMin":21}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
### Advertising rules
- Selling the service to hosts only. Alcohol in the picture → 21+ audience.
- Never a recruiting ad ('Hiring bartenders'): that is Meta's Employment category, a different campaign.
Trade-specific excluded terms: none configured.
### Catalog notes
Bartending pictures trigger the alcohol rules (21+). Recruiting would need the Employment special category.
### Catalog sources
- https://transparency.meta.com/policies/ad-standards/restricted-goods-services/alcohol/
## Photographers
Slug: `photographer`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Wedding photographers
Slug: `wedding-photographer`. Location model: area.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
### Advertising rules
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Event planners
Slug: `event-planner`. Location model: area.
Configured platform guidance: {"googleSearch":true,"ageMin":21}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
### Advertising rules
- Alcohol in the picture → 21+ audience.
Trade-specific excluded terms: none configured.
### Catalog notes
Nothing specific on Meta or Google.
## Chiropractors
Slug: `chiropractor`. Location model: office.
Configured platform guidance: {"googleSearch":true,"healthPixelRisk":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer a free or discounted first visit?** (`flFreeExamNotice`): Florida law (456.062): an ad with a free or discounted offer from a health practitioner must carry the statutory 72-hour refund notice. Yes = your ads get the notice. States: FL. Collected: before-ads.
### Advertising rules
- Name the relief or the service, never the reader's condition: 'Back pain relief' yes, 'Do you have back pain?' no. (Meta Personal Attributes)
- No promised outcome, no 'cure', no 'in one visit'. (Meta Health & Wellness, Google Unreliable claims)
- No before/after for chiropractic; dental cosmetic before/after only to 18+.
Trade-specific excluded terms: cure, pain-free, do you have, suffering from.
### Catalog notes
Meta may classify the pixel as 'Health & Wellness' and block the Lead event: check Events Manager → Data Source Categories on the tenant's account before promising leads. Funnel answers are health data (WA MHMDA): never send them to the pixel; separate opt-in. HIPAA is the practice's side.
### Catalog sources
- https://transparency.meta.com/policies/ad-standards/objectionable-content/privacy-violations-personal-attributes/
- https://transparency.meta.com/policies/ad-standards/restricted-goods-services/health-wellness/
- https://www.flsenate.gov/Laws/Statutes/2024/0456.062
## Dentists
Slug: `dentist`. Location model: office.
Configured platform guidance: {"googleSearch":true,"ageMin":18,"healthPixelRisk":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
- **Do you offer a free or discounted first visit?** (`flFreeExamNotice`): Florida law (456.062): an ad with a free or discounted offer from a health practitioner must carry the statutory 72-hour refund notice. Yes = your ads get the notice. States: FL. Collected: before-ads.
### Advertising rules
- Name the relief or the service, never the reader's condition: 'Back pain relief' yes, 'Do you have back pain?' no. (Meta Personal Attributes)
- No promised outcome, no 'cure', no 'in one visit'. (Meta Health & Wellness, Google Unreliable claims)
- No before/after for chiropractic; dental cosmetic before/after only to 18+.
- No 'specialist' (state dental boards regulate the word).
Trade-specific excluded terms: cure, specialist, do you have, painless.
### Catalog notes
Same pixel risk as chiropractor. Cosmetic before/after allowed to adults. Google LSA needs licence + NPI.
### Catalog sources
- https://transparency.meta.com/policies/ad-standards/restricted-goods-services/health-wellness/
- https://www.flsenate.gov/Laws/Statutes/2024/0456.062
## Personal trainers
Slug: `personal-trainer`. Location model: area.
Configured platform guidance: {"googleSearch":true,"ageMin":18,"healthPixelRisk":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
### Advertising rules
- Energy, routine, community. Never a statement of inferiority about the body, no 'pinching fat', no sensational weight-loss claims.
- Before/after only with a typical, plausible result and an 18+ audience.
Trade-specific excluded terms: lose 20 lbs, overweight, fat, transform your body.
### Catalog notes
Meta's fitness rules are about body image; the FTC requires weight-loss claims to be substantiated.
### Catalog sources
- https://transparency.meta.com/policies/ad-standards/restricted-goods-services/health-wellness/
## Hair salons
Slug: `hair-salon`. Location model: office.
Configured platform guidance: {"googleSearch":true}. These flags do not make the corresponding advertising channel available through v1.
### Fields to collect
### Advertising rules
- Colour, cuts, bridal. No statements of inferiority ('tired of your hair?').
Trade-specific excluded terms: none configured.
### Catalog notes
Non-permanent beauty is exempt from Meta's 18+ rule.
## Read the catalog from your integration [#read-the-catalog-from-your-integration]
```bash
curl https://api.benjiads.com/v1/verticals \
-H "Authorization: Bearer $BENJIADS_API_KEY"
curl https://api.benjiads.com/v1/verticals/plumber \
-H "Authorization: Bearer $BENJIADS_API_KEY"
```
MCP tools: `list_verticals` and `get_vertical`. Both require `site:read`.
`requiredIn` identifies states where a field applies. `askAt` indicates when to collect it. `launch: "hold"` means the catalog keeps the vertical but advertising is on hold. Platform flags describe configured policy guidance; they do not create support for a channel in the public API.
## Configuration and execution [#configuration-and-execution]
The catalog includes onboarding and copy guidance. The current shared license gate specifically evaluates `licenseNumber` against the selected states. Other fields, such as `securityLicense` or `flFreeExamNotice`, describe information to collect and content restrictions; do not assume every field has an automated registry check.
Use `get_workspace_requirements` to inspect the current workspace's license blockers. Subscription, funding, billing pauses, and job completion are validated separately when preparing or launching advertising.
A missing catalog rule does not establish that a business has no state or local requirements. The catalog's linked sources provide the context for each configured policy.
# List supported verticals and rules
Published trade catalog with configured state-specific fields, ad-copy restrictions and platform guidance. A published vertical can still be on hold. Configuration flags do not enable a new advertising channel.
URL: https://benjiads.com/docs/api/list-verticals
## GET /verticals
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "list_verticals",
"summary": "List supported verticals and rules",
"description": "Published trade catalog with configured state-specific fields, ad-copy restrictions and platform guidance. A published vertical can still be on hold. Configuration flags do not enable a new advertising channel.",
"tags": [
"verticals"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:read"
]
}
],
"x-required-scope": "site:read",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"verticals": {
"type": "array",
"items": {
"type": "object",
"properties": {
"slug": {
"type": "string"
},
"label": {
"type": "string"
},
"singular": {
"type": "string"
},
"locationKind": {
"type": "string"
},
"compliance": {
"type": [
"object",
"null"
],
"properties": {
"launch": {
"type": "string",
"enum": [
"go",
"hold"
]
},
"platform": {
"type": "object",
"properties": {
"googleSearch": {
"type": "boolean"
},
"metaSpecialAdCategory": {
"type": "string",
"enum": [
"housing",
"employment",
"credit"
]
},
"ageMin": {
"type": "number"
},
"healthPixelRisk": {
"type": "boolean"
}
},
"required": [
"googleSearch"
],
"additionalProperties": false
},
"adRules": {
"type": "array",
"items": {
"type": "string"
}
},
"avoid": {
"type": "array",
"items": {
"type": "string"
}
},
"tenantFields": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
},
"askAt": {
"type": "string",
"enum": [
"onboarding",
"before-ads"
]
},
"requiredIn": {
"type": "array",
"items": {
"type": "string"
}
},
"why": {
"type": "string"
}
},
"required": [
"key",
"label",
"askAt",
"why"
],
"additionalProperties": false
}
},
"disclosures": {
"type": "array",
"items": {
"type": "object",
"properties": {
"states": {
"type": "array",
"items": {
"type": "string"
}
},
"text": {
"type": "string"
}
},
"required": [
"states",
"text"
],
"additionalProperties": false
}
},
"notes": {
"type": "string"
},
"sources": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"launch",
"platform",
"adRules",
"avoid",
"tenantFields",
"disclosures",
"notes",
"sources"
],
"additionalProperties": false
}
},
"required": [
"slug",
"label",
"singular",
"locationKind",
"compliance"
],
"additionalProperties": false
}
},
"globalAvoid": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"verticals",
"globalAvoid"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read a vertical's requirements
Read the full configured rule sheet for a trade such as plumber, including requiredIn states and disclosures. Check get_workspace_requirements for the current workspace's license blockers.
URL: https://benjiads.com/docs/api/get-vertical
## GET /verticals/{slug}
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_vertical",
"summary": "Read a vertical's requirements",
"description": "Read the full configured rule sheet for a trade such as plumber, including requiredIn states and disclosures. Check get_workspace_requirements for the current workspace's license blockers.",
"tags": [
"verticals"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:read"
]
}
],
"x-required-scope": "site:read",
"parameters": [
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^[a-z0-9-]{2,60}$"
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"vertical": {
"type": "object",
"properties": {
"slug": {
"type": "string"
},
"label": {
"type": "string"
},
"singular": {
"type": "string"
},
"locationKind": {
"type": "string"
},
"compliance": {
"type": [
"object",
"null"
],
"properties": {
"launch": {
"type": "string",
"enum": [
"go",
"hold"
]
},
"platform": {
"type": "object",
"properties": {
"googleSearch": {
"type": "boolean"
},
"metaSpecialAdCategory": {
"type": "string",
"enum": [
"housing",
"employment",
"credit"
]
},
"ageMin": {
"type": "number"
},
"healthPixelRisk": {
"type": "boolean"
}
},
"required": [
"googleSearch"
],
"additionalProperties": false
},
"adRules": {
"type": "array",
"items": {
"type": "string"
}
},
"avoid": {
"type": "array",
"items": {
"type": "string"
}
},
"tenantFields": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
},
"askAt": {
"type": "string",
"enum": [
"onboarding",
"before-ads"
]
},
"requiredIn": {
"type": "array",
"items": {
"type": "string"
}
},
"why": {
"type": "string"
}
},
"required": [
"key",
"label",
"askAt",
"why"
],
"additionalProperties": false
}
},
"disclosures": {
"type": "array",
"items": {
"type": "object",
"properties": {
"states": {
"type": "array",
"items": {
"type": "string"
}
},
"text": {
"type": "string"
}
},
"required": [
"states",
"text"
],
"additionalProperties": false
}
},
"notes": {
"type": "string"
},
"sources": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"launch",
"platform",
"adRules",
"avoid",
"tenantFields",
"disclosures",
"notes",
"sources"
],
"additionalProperties": false
}
},
"required": [
"slug",
"label",
"singular",
"locationKind",
"compliance"
],
"additionalProperties": false
}
},
"required": [
"vertical"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Check workspace license requirements
Resolve the workspace's selected states against its trade rules and the existing license acceptance checks. missing lists actual license blockers. Other configured fields guide onboarding and ad copy; their presence does not imply an automated registry check. Billing, funding and job completion are checked separately on launch.
URL: https://benjiads.com/docs/api/get-workspace-requirements
## GET /workspace/requirements
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_workspace_requirements",
"summary": "Check workspace license requirements",
"description": "Resolve the workspace's selected states against its trade rules and the existing license acceptance checks. missing lists actual license blockers. Other configured fields guide onboarding and ad copy; their presence does not imply an automated registry check. Billing, funding and job completion are checked separately on launch.",
"tags": [
"workspace"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:read"
]
}
],
"x-required-scope": "site:read",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string"
},
"vertical": {
"type": "string"
},
"states": {
"type": "array",
"items": {
"type": "string"
}
},
"fields": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
},
"askAt": {
"type": "string",
"enum": [
"onboarding",
"before-ads"
]
},
"requiredIn": {
"type": "array",
"items": {
"type": "string"
}
},
"why": {
"type": "string"
}
},
"required": [
"key",
"label",
"askAt",
"why"
],
"additionalProperties": false
}
},
"missing": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
},
"states": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"key",
"label",
"states"
],
"additionalProperties": false
}
},
"licenseLine": {
"type": [
"string",
"null"
]
},
"disclosures": {
"type": "array",
"items": {
"type": "string"
}
},
"manageUrl": {
"type": "string",
"format": "uri"
}
},
"required": [
"workspaceId",
"vertical",
"states",
"fields",
"missing",
"licenseLine",
"disclosures",
"manageUrl"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read your workspace
Returns only the workspace authorized by this connection.
URL: https://benjiads.com/docs/api/get-workspace
## GET /workspace
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_workspace",
"summary": "Read your workspace",
"description": "Returns only the workspace authorized by this connection.",
"tags": [
"workspace"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:read"
]
}
],
"x-required-scope": "site:read",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspace": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"slug": {
"type": "string"
},
"displayName": {
"type": "string"
},
"siteUrl": {
"type": "string",
"format": "uri"
}
},
"required": [
"id",
"slug",
"displayName",
"siteUrl"
],
"additionalProperties": false
},
"scopes": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"workspace",
"scopes"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read the site and its draft
Read published content and the current draft. Available without a paid subscription.
URL: https://benjiads.com/docs/api/get-site
## GET /site
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_site",
"summary": "Read the site and its draft",
"description": "Read published content and the current draft. Available without a paid subscription.",
"tags": [
"site"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:read"
]
}
],
"x-required-scope": "site:read",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"site": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"slug": {
"type": "string"
},
"displayName": {
"type": "string"
},
"status": {
"type": "string"
},
"tagline": {
"type": [
"string",
"null"
]
},
"bio": {
"type": [
"string",
"null"
]
},
"photoUrl": {
"type": [
"string",
"null"
]
},
"phonePublic": {
"type": [
"string",
"null"
]
},
"theme": {
"type": "string"
},
"accentColor": {
"type": [
"string",
"null"
]
},
"brandWordmarkUrl": {
"type": [
"string",
"null"
]
},
"brandWordmarkWhiteUrl": {
"type": [
"string",
"null"
]
},
"locations": {},
"links": {},
"socials": {},
"siteDoc": {},
"siteDraft": {}
},
"required": [
"id",
"slug",
"displayName",
"status",
"tagline",
"bio",
"photoUrl",
"phonePublic",
"theme",
"accentColor"
],
"additionalProperties": false
}
},
"required": [
"site"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Update site settings
Update business details, appearance, service areas or publication status. Lead capture remains available without a subscription.
URL: https://benjiads.com/docs/api/update-site
## PATCH /site
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "update_site",
"summary": "Update site settings",
"description": "Update business details, appearance, service areas or publication status. Lead capture remains available without a subscription.",
"tags": [
"site"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:write"
]
}
],
"x-required-scope": "site:write",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"description": "8–80 letters, digits, underscores or hyphens. Reuse the same key and arguments for retries. Completed mutations replay for at least 90 days; a pending operation returns 409 and must be reconciled before using a new key.",
"schema": {
"type": "string",
"minLength": 8,
"maxLength": 80,
"pattern": "^[A-Za-z0-9_-]+$"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"displayName": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"tagline": {
"type": [
"string",
"null"
],
"maxLength": 160
},
"bio": {
"type": [
"string",
"null"
],
"maxLength": 2000
},
"photoUrl": {
"type": [
"string",
"null"
],
"format": "uri",
"maxLength": 1000
},
"locations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"maxLength": 48
},
"label": {
"type": "string",
"maxLength": 120
},
"city": {
"type": "string",
"maxLength": 80
},
"state": {
"type": "string",
"maxLength": 2
},
"lat": {
"type": "number",
"minimum": -90,
"maximum": 90
},
"lon": {
"type": "number",
"minimum": -180,
"maximum": 180
},
"radiusMi": {
"type": "number",
"minimum": 1,
"maximum": 100
}
},
"required": [
"lat",
"lon"
],
"additionalProperties": false
},
"maxItems": 7
},
"phonePublic": {
"type": [
"string",
"null"
],
"maxLength": 40
},
"theme": {
"type": "string",
"enum": [
"electric",
"midnight",
"sky"
]
},
"accentColor": {
"type": [
"string",
"null"
],
"pattern": "^#[0-9a-fA-F]{6}$"
},
"brandWordmarkUrl": {
"type": [
"string",
"null"
],
"format": "uri",
"maxLength": 1000
},
"brandWordmarkWhiteUrl": {
"type": [
"string",
"null"
],
"format": "uri",
"maxLength": 1000
},
"links": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"minLength": 1,
"maxLength": 60
},
"url": {
"type": "string",
"format": "uri",
"maxLength": 500
}
},
"required": [
"label",
"url"
],
"additionalProperties": false
},
"maxItems": 20
},
"socials": {
"type": "object",
"properties": {
"instagram": {
"type": "string",
"maxLength": 300
},
"facebook": {
"type": "string",
"maxLength": 300
},
"tiktok": {
"type": "string",
"maxLength": 300
},
"youtube": {
"type": "string",
"maxLength": 300
},
"website": {
"type": "string",
"maxLength": 300
},
"email": {
"type": "string",
"maxLength": 120
}
},
"additionalProperties": false
},
"status": {
"type": "string",
"enum": [
"DRAFT",
"LIVE"
]
},
"trust": {
"type": "object",
"properties": {
"startedYear": {
"type": "integer"
},
"credentials": {
"type": "array",
"items": {
"type": "string"
}
},
"statLines": {
"type": "array",
"items": {
"type": "object",
"properties": {
"value": {
"type": "string"
},
"label": {
"type": "string"
}
},
"required": [
"value",
"label"
],
"additionalProperties": false
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
}
}
},
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"site": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"slug": {
"type": "string"
},
"displayName": {
"type": "string"
},
"status": {
"type": "string"
},
"tagline": {
"type": [
"string",
"null"
]
},
"bio": {
"type": [
"string",
"null"
]
},
"photoUrl": {
"type": [
"string",
"null"
]
},
"phonePublic": {
"type": [
"string",
"null"
]
},
"theme": {
"type": "string"
},
"accentColor": {
"type": [
"string",
"null"
]
},
"brandWordmarkUrl": {
"type": [
"string",
"null"
]
},
"brandWordmarkWhiteUrl": {
"type": [
"string",
"null"
]
},
"locations": {},
"links": {},
"socials": {},
"siteDoc": {},
"siteDraft": {}
},
"required": [
"id",
"slug",
"displayName",
"status",
"tagline",
"bio",
"photoUrl",
"phonePublic",
"theme",
"accentColor"
],
"additionalProperties": false
}
},
"required": [
"site"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Save a site draft
Save a Benjiads site document using the same structural validation as the site builder. Get the existing document with get_site before editing.
URL: https://benjiads.com/docs/api/save-site-draft
## PUT /site/draft
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "save_site_draft",
"summary": "Save a site draft",
"description": "Save a Benjiads site document using the same structural validation as the site builder. Get the existing document with get_site before editing.",
"tags": [
"site"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:write"
]
}
],
"x-required-scope": "site:write",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"description": "8–80 letters, digits, underscores or hyphens. Reuse the same key and arguments for retries. Completed mutations replay for at least 90 days; a pending operation returns 409 and must be reconciled before using a new key.",
"schema": {
"type": "string",
"minLength": 8,
"maxLength": 80,
"pattern": "^[A-Za-z0-9_-]+$"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"doc": {
"type": "object",
"additionalProperties": {}
}
},
"required": [
"doc"
],
"additionalProperties": false
}
}
}
},
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"site": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"slug": {
"type": "string"
},
"displayName": {
"type": "string"
},
"status": {
"type": "string"
},
"tagline": {
"type": [
"string",
"null"
]
},
"bio": {
"type": [
"string",
"null"
]
},
"photoUrl": {
"type": [
"string",
"null"
]
},
"phonePublic": {
"type": [
"string",
"null"
]
},
"theme": {
"type": "string"
},
"accentColor": {
"type": [
"string",
"null"
]
},
"brandWordmarkUrl": {
"type": [
"string",
"null"
]
},
"brandWordmarkWhiteUrl": {
"type": [
"string",
"null"
]
},
"locations": {},
"links": {},
"socials": {},
"siteDoc": {},
"siteDraft": {}
},
"required": [
"id",
"slug",
"displayName",
"status",
"tagline",
"bio",
"photoUrl",
"phonePublic",
"theme",
"accentColor"
],
"additionalProperties": false
}
},
"required": [
"site"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Publish the saved site draft
Publishes the saved draft to the live site. Review the draft first. Available without a paid subscription.
URL: https://benjiads.com/docs/api/publish-site
## POST /site/publish
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "publish_site",
"summary": "Publish the saved site draft",
"description": "Publishes the saved draft to the live site. Review the draft first. Available without a paid subscription.",
"tags": [
"site"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"site:write"
]
}
],
"x-required-scope": "site:write",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"description": "8–80 letters, digits, underscores or hyphens. Reuse the same key and arguments for retries. Completed mutations replay for at least 90 days; a pending operation returns 409 and must be reconciled before using a new key.",
"schema": {
"type": "string",
"minLength": 8,
"maxLength": 80,
"pattern": "^[A-Za-z0-9_-]+$"
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"site": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"slug": {
"type": "string"
},
"displayName": {
"type": "string"
},
"status": {
"type": "string"
},
"tagline": {
"type": [
"string",
"null"
]
},
"bio": {
"type": [
"string",
"null"
]
},
"photoUrl": {
"type": [
"string",
"null"
]
},
"phonePublic": {
"type": [
"string",
"null"
]
},
"theme": {
"type": "string"
},
"accentColor": {
"type": [
"string",
"null"
]
},
"brandWordmarkUrl": {
"type": [
"string",
"null"
]
},
"brandWordmarkWhiteUrl": {
"type": [
"string",
"null"
]
},
"locations": {},
"links": {},
"socials": {},
"siteDoc": {},
"siteDraft": {}
},
"required": [
"id",
"slug",
"displayName",
"status",
"tagline",
"bio",
"photoUrl",
"phonePublic",
"theme",
"accentColor"
],
"additionalProperties": false
}
},
"required": [
"site"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read campaigns and ad balance
Money is in USD wallet cents. balanceCents is cumulative funding; remainingCents is available funding. If the provider is unavailable, spending may use the stored lifetime mirror.
URL: https://benjiads.com/docs/api/list-campaigns
## GET /campaigns
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "list_campaigns",
"summary": "Read campaigns and ad balance",
"description": "Money is in USD wallet cents. balanceCents is cumulative funding; remainingCents is available funding. If the provider is unavailable, spending may use the stored lifetime mirror.",
"tags": [
"campaigns"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"ads:read"
]
}
],
"x-required-scope": "ads:read",
"parameters": [
{
"name": "preset",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"not": {}
},
{
"type": "string",
"enum": [
"today",
"yesterday",
"last_7d",
"maximum"
]
}
]
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"balanceCents": {
"type": "number"
},
"remainingCents": {
"type": "number"
},
"spentCents": {
"type": "number"
},
"spentLifetimeCents": {
"type": "number"
},
"exhausted": {
"type": "boolean"
},
"masterStatus": {
"type": [
"string",
"null"
]
},
"campaigns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"status": {
"type": "string"
},
"dailyBudgetCents": {
"type": "number"
},
"budgetCents": {
"type": "number"
},
"spendCents": {
"type": "number"
},
"createdAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"status"
],
"additionalProperties": false
}
}
},
"required": [
"balanceCents",
"remainingCents",
"spentCents",
"spentLifetimeCents",
"exhausted",
"masterStatus",
"campaigns"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Prepare a campaign
Queues preparation with launch disabled. Requires the existing subscription, wallet, creative ownership and licence checks. Returns a job to poll. dailyBudgetCents is the TOTAL across locations.
URL: https://benjiads.com/docs/api/create-campaign
## POST /campaigns
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "create_campaign",
"summary": "Prepare a campaign",
"description": "Queues preparation with launch disabled. Requires the existing subscription, wallet, creative ownership and licence checks. Returns a job to poll. dailyBudgetCents is the TOTAL across locations.",
"tags": [
"campaigns"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"ads:write"
]
}
],
"x-required-scope": "ads:write",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"description": "8–80 letters, digits, underscores or hyphens. Reuse the same key and arguments for retries. Completed mutations replay for at least 90 days; a pending operation returns 409 and must be reconciled before using a new key.",
"schema": {
"type": "string",
"minLength": 8,
"maxLength": 80,
"pattern": "^[A-Za-z0-9_-]+$"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"messages": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 400
},
"minItems": 1,
"maxItems": 5
},
"headlines": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 60
},
"minItems": 1,
"maxItems": 5
},
"descriptions": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"minItems": 1,
"maxItems": 2
},
"dailyBudgetCents": {
"type": "integer"
},
"creativeIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"maxItems": 18
},
"creativeId": {
"type": "string",
"format": "uuid"
},
"radiusMi": {
"type": "integer",
"minimum": 10,
"maximum": 50
},
"extraLocations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"lat": {
"type": "number",
"minimum": -90,
"maximum": 90
},
"lon": {
"type": "number",
"minimum": -180,
"maximum": 180
}
},
"required": [
"lat",
"lon"
],
"additionalProperties": false
},
"maxItems": 10
}
},
"required": [
"dailyBudgetCents"
],
"additionalProperties": false
}
}
}
},
"responses": {
"202": {
"description": "Queued; poll the returned job ID.",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"job": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
},
"hold": {
"type": [
"string",
"null"
]
},
"attempts": {
"type": "number"
},
"adsWanted": {
"type": "number"
},
"adsCreated": {
"type": "number"
},
"campaignId": {
"type": [
"string",
"null"
]
},
"liveAt": {
"type": [
"string",
"null"
]
},
"nextRunAt": {
"type": [
"string",
"null"
]
},
"lastError": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"status",
"hold",
"attempts",
"adsWanted",
"adsCreated",
"campaignId",
"liveAt",
"nextRunAt",
"lastError"
],
"additionalProperties": false
}
},
"required": [
"job"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read campaign preparation status
Poll an existing deployment job. ready means prepared; live means delivery was activated. A failed or cancelled job may have created provider objects.
URL: https://benjiads.com/docs/api/get-job
## GET /jobs/{id}
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_job",
"summary": "Read campaign preparation status",
"description": "Poll an existing deployment job. ready means prepared; live means delivery was activated. A failed or cancelled job may have created provider objects.",
"tags": [
"jobs"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"ads:read"
]
}
],
"x-required-scope": "ads:read",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"job": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
},
"hold": {
"type": [
"string",
"null"
]
},
"attempts": {
"type": "number"
},
"adsWanted": {
"type": "number"
},
"adsCreated": {
"type": "number"
},
"campaignId": {
"type": [
"string",
"null"
]
},
"liveAt": {
"type": [
"string",
"null"
]
},
"nextRunAt": {
"type": [
"string",
"null"
]
},
"lastError": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"status",
"hold",
"attempts",
"adsWanted",
"adsCreated",
"campaignId",
"liveAt",
"nextRunAt",
"lastError"
],
"additionalProperties": false
}
},
"required": [
"job"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Launch a prepared campaign
Starts ad delivery using the campaign's saved budget. Requires an active entitlement, available funding and completed preparation with required licences. Authorize the budget before calling.
URL: https://benjiads.com/docs/api/launch-campaign
## POST /campaigns/{id}/launch
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "launch_campaign",
"summary": "Launch a prepared campaign",
"description": "Starts ad delivery using the campaign's saved budget. Requires an active entitlement, available funding and completed preparation with required licences. Authorize the budget before calling.",
"tags": [
"campaigns"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"ads:write"
]
}
],
"x-required-scope": "ads:write",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"description": "8–80 letters, digits, underscores or hyphens. Reuse the same key and arguments for retries. Completed mutations replay for at least 90 days; a pending operation returns 409 and must be reconciled before using a new key.",
"schema": {
"type": "string",
"minLength": 8,
"maxLength": 80,
"pattern": "^[A-Za-z0-9_-]+$"
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"campaign": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"status": {
"type": "string"
},
"dailyBudgetCents": {
"type": "number"
},
"budgetCents": {
"type": "number"
},
"spendCents": {
"type": "number"
},
"createdAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"status"
],
"additionalProperties": false
}
},
"required": [
"campaign"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Pause a campaign
Pauses the selected campaign using the existing product access rules.
URL: https://benjiads.com/docs/api/pause-campaign
## POST /campaigns/{id}/pause
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "pause_campaign",
"summary": "Pause a campaign",
"description": "Pauses the selected campaign using the existing product access rules.",
"tags": [
"campaigns"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"ads:write"
]
}
],
"x-required-scope": "ads:write",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"description": "8–80 letters, digits, underscores or hyphens. Reuse the same key and arguments for retries. Completed mutations replay for at least 90 days; a pending operation returns 409 and must be reconciled before using a new key.",
"schema": {
"type": "string",
"minLength": 8,
"maxLength": 80,
"pattern": "^[A-Za-z0-9_-]+$"
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"campaign": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"status": {
"type": "string"
},
"dailyBudgetCents": {
"type": "number"
},
"budgetCents": {
"type": "number"
},
"spendCents": {
"type": "number"
},
"createdAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"status"
],
"additionalProperties": false
}
},
"required": [
"campaign"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read business performance
Returns the dashboard's lead and site performance. days=1 uses a 48-hour hourly series and rolling totals; days=7 or 30 uses daily points.
URL: https://benjiads.com/docs/api/get-metrics
## GET /metrics
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_metrics",
"summary": "Read business performance",
"description": "Returns the dashboard's lead and site performance. days=1 uses a 48-hour hourly series and rolling totals; days=7 or 30 uses daily points.",
"tags": [
"metrics"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"metrics:read"
]
}
],
"x-required-scope": "metrics:read",
"parameters": [
{
"name": "days",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"not": {}
},
{
"type": "string",
"enum": [
"1",
"7",
"30"
]
}
]
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {}
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read leads
Contact details stay masked when the workspace has no paid entitlement. Follow nextCursor for pagination.
URL: https://benjiads.com/docs/api/list-leads
## GET /leads
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "list_leads",
"summary": "Read leads",
"description": "Contact details stay masked when the workspace has no paid entitlement. Follow nextCursor for pagination.",
"tags": [
"leads"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"leads:read"
]
}
],
"x-required-scope": "leads:read",
"parameters": [
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"not": {}
},
{
"type": "integer",
"minimum": 1,
"maximum": 200
}
]
}
},
{
"name": "cursor",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"not": {}
},
{
"type": "string",
"format": "uuid"
}
]
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"leads": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": {}
}
},
"gated": {
"type": "boolean"
},
"nextCursor": {
"type": [
"string",
"null"
]
}
},
"required": [
"leads",
"gated",
"nextCursor"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read subscription status
Read the workspace's current entitlement. active includes an eligible trial, as in the dashboard.
URL: https://benjiads.com/docs/api/get-subscription
## GET /billing/subscription
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_subscription",
"summary": "Read subscription status",
"description": "Read the workspace's current entitlement. active includes an eligible trial, as in the dashboard.",
"tags": [
"billing"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"billing:read"
]
}
],
"x-required-scope": "billing:read",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": [
"string",
"null"
]
},
"currentPeriodEnd": {
"type": [
"string",
"null"
]
},
"checkoutUrl": {
"type": "string",
"format": "uri"
}
},
"required": [
"status",
"currentPeriodEnd",
"checkoutUrl"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Open subscription checkout
Returns a browser handoff to the existing Benjiads checkout. The owner signs in and authorizes the recurring subscription; this call does not charge a card or grant access. Existing subscribers can manage billing there.
URL: https://benjiads.com/docs/api/start-subscription
## POST /billing/checkout
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "start_subscription",
"summary": "Open subscription checkout",
"description": "Returns a browser handoff to the existing Benjiads checkout. The owner signs in and authorizes the recurring subscription; this call does not charge a card or grant access. Existing subscribers can manage billing there.",
"tags": [
"billing"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"billing:write"
]
}
],
"x-required-scope": "billing:write",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"description": "8–80 letters, digits, underscores or hyphens. Reuse the same key and arguments for retries. Completed mutations replay for at least 90 days; a pending operation returns 409 and must be reconciled before using a new key.",
"schema": {
"type": "string",
"minLength": 8,
"maxLength": 80,
"pattern": "^[A-Za-z0-9_-]+$"
}
}
],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"action": {
"type": "string",
"enum": [
"complete_in_browser"
]
}
},
"required": [
"url",
"action"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read subscription invoices
Lists invoices for this workspace's Benjiads subscription only.
URL: https://benjiads.com/docs/api/list-invoices
## GET /billing/invoices
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "list_invoices",
"summary": "Read subscription invoices",
"description": "Lists invoices for this workspace's Benjiads subscription only.",
"tags": [
"billing"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"billing:read"
]
}
],
"x-required-scope": "billing:read",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"invoices": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": {}
}
}
},
"required": [
"invoices"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```
# Read integration usage
Returns admitted REST and MCP operations for the last 30 days, grouped by operation. These are operational counters, not additional billable units.
URL: https://benjiads.com/docs/api/get-usage
## GET /usage
Base URL: https://api.benjiads.com/v1
Bearer authentication is required.
```json
{
"operationId": "get_usage",
"summary": "Read integration usage",
"description": "Returns admitted REST and MCP operations for the last 30 days, grouped by operation. These are operational counters, not additional billable units.",
"tags": [
"usage"
],
"security": [
{
"ApiKey": []
},
{
"OAuth": [
"metrics:read"
]
}
],
"x-required-scope": "metrics:read",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"headers": {
"X-Request-Id": {
"schema": {
"type": "string"
},
"description": "Operation receipt ID"
},
"Idempotency-Replayed": {
"schema": {
"type": "string",
"enum": [
"true"
]
},
"description": "Present for a replay"
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"since": {
"type": "string"
},
"requests": {
"type": "number"
},
"operations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"operation": {
"type": "string"
},
"count": {
"type": "number"
}
},
"required": [
"operation",
"count"
],
"additionalProperties": false
}
},
"limits": {
"type": "object",
"properties": {
"requestsPerMinute": {
"type": "number"
},
"writesPerMinute": {
"type": "number"
}
},
"required": [
"requestsPerMinute",
"writesPerMinute"
],
"additionalProperties": false
}
},
"required": [
"since",
"requests",
"operations",
"limits"
],
"additionalProperties": false
}
}
}
},
"400": {
"description": "Invalid input or missing idempotency key",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"401": {
"description": "Missing, expired or revoked credential",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"402": {
"description": "Subscription required",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"403": {
"description": "Missing scope or workspace access",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"404": {
"description": "Resource not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"409": {
"description": "State conflict, operation pending or idempotency conflict",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"413": {
"description": "Request body exceeds 512 KiB",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"429": {
"description": "Rate limited; retry after 60 seconds",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"500": {
"description": "Internal failure; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"502": {
"description": "Provider unavailable",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"503": {
"description": "Service not configured",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
}
}
}
```