REST API

Developer API

Programmatic access to the Boatwork contractor network. Search and filter marine service professionals by specialty, location, and rating.

✓ Bearer token auth✓ JSON responses✓ 500 req / day free

Authentication

All authenticated requests use a Bearer token in the Authorization header. Public API keys begin with bw_public_.

Example request
curl https://boatwork.co/api/v1/public/contractors/search \
  -H "Authorization: Bearer bw_public_your_key_here" \
  -G --data-urlencode "q=yacht detailing"

Get your API key from your developer console → API Keys or — if you’re an AI agent — self-register (no human in the loop, see below).

Rate Limits

Public API keys are limited to 500 requests per 24-hour rolling window. When the limit is exceeded the API returns 429 Too Many Requests with a Retry-After header indicating seconds to wait.

500requests / 24 hrs

Need higher limits? Questions? Sign in and use the feedback form, or email support@boatwork.co.

For AI Agents

Self-register, get a working API key in one POST, no human gate.

POST/api/agents/register

Creates an agent identity (a User row with isAgent = true) and mints the initial bw_public_* key. The plaintext key + email are returned ONCE — capture them now.

ParameterTypeDescription
firstName*stringDisplay first name.
lastName*stringDisplay last name.
email*stringUnique email; used for the sign-in flow.
password*stringMinimum 10 characters. Hashed with argon2 server-side.
purposestringOptional free-text describing what this agent does.
Example request
curl -X POST https://boatwork.co/api/agents/register \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Andi",
    "lastName": "Moore",
    "email": "andi-agent@example.com",
    "password": "a-strong-password-of-at-least-10-chars",
    "purpose": "Handles marina onboarding triage."
  }'
Example response
{
  "success": true,
  "data": {
    "agent": { "id": "...", "firstName": "Andi", "lastName": "Moore", "email": "andi-agent@example.com", "isAdmin": false, "isAgent": true },
    "credentials": {
      "email": "andi-agent@example.com",
      "apiKey": "bw_public_abcdef1234567890",
      "apiKeyPrefix": "bw_public_abcdef",
      "apiBase": "https://boatwork.co/api/v1/public",
      "howToUse": "Send `Authorization: Bearer <apiKey>` on every request."
    }
  }
}

Email already in use? Pick a different one (e.g. andi-agent@boatwork.co). If you legitimately own the email and want to recover, contact the admin.

GET/api/account/me

Returns your current role + a convenience canMintAdminKeys flag. Poll this if you’re waiting for an admin to elevate you to admin tier — when isAdmin: true, your next minted key becomes a bw_live_*admin key automatically.

Example response
{
  "success": true,
  "data": {
    "id": "...",
    "firstName": "Andi",
    "lastName": "Moore",
    "email": "andi-agent@example.com",
    "isAgent": true,
    "isAdmin": false,
    "canMintAdminKeys": false
  }
}
POST/api/v1/user-api-keys

Mint additional keys. Authenticated agents get one of two key shapes based on role: bw_public_* for public-tier users, bw_live_* for admin-tier (after elevation). Max 5 active keys for admins/agents, 2 for humans.

Example request
curl -X POST https://boatwork.co/api/v1/user-api-keys \
  -H "Authorization: Bearer bw_public_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "rotation 2026-05"}'

Discovery shortcut: the same information is available machine-readable at /.well-known/agent.json, in the public OpenAPI spec at /developers/openapi.json, and as a bootstrap recipe inside /llms.txt.

Public API Endpoints

Base URL: https://boatwork.co

GET/api/v1/public/contractors/search

Search active contractors by keyword, specialty, city, or state.

ParameterTypeDescription
qstringText search on name, description, and location
specialtystringSpecialty slug (e.g. yacht-detailing). See /specialties endpoint.
citystringCity filter (case-insensitive partial match)
statestringState filter (e.g. FL)
pageintegerPage number (1–3 max)
limitintegerResults per page (max 20, default 20)
Example request
curl "https://boatwork.co/api/v1/public/contractors/search?q=engine+repair&state=FL&limit=5" \
  -H "Authorization: Bearer bw_public_your_key_here"
Example response
{
  "success": true,
  "data": {
    "contractors": [
      {
        "id": "clt_abc123",
        "slug": "marine-engines-miami",
        "name": "Marine Engines Miami",
        "tagline": "Certified outboard & inboard specialists",
        "location": "Miami, FL",
        "geocodedCity": "Miami",
        "geocodedState": "FL",
        "avatarUrl": "https://example.com/logo.jpg",
        "googleRating": 4.8,
        "googleReviewCount": 142,
        "isVerified": true,
        "isClaimed": true,
        "phone": "+1-305-555-0100",
        "email": "info@marineenginesmiami.com",
        "websiteUrl": "https://marineenginesmiami.com",
        "specialities": [
          { "id": "sp_1", "name": "Engine Repair", "slug": "engine-repair" }
        ]
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 5,
      "total": 38,
      "totalPages": 3
    }
  }
}
GET/api/v1/public/contractors/geo-search

Find contractors within a radius of a point, or within a bounding box. Returns distance from the search point (point mode only).

ParameterTypeDescription
latfloatLatitude of search point (point mode)
lngfloatLongitude of search point (point mode)
radiusfloatSearch radius in miles (default 30, point mode)
minLatfloatMinimum latitude (bbox mode)
maxLatfloatMaximum latitude (bbox mode)
minLngfloatMinimum longitude (bbox mode)
maxLngfloatMaximum longitude (bbox mode)
specialtySlugstringFilter by specialty slug
minRatingfloatMinimum Google rating (e.g. 4.0)
limitintegerMax results (default 100, max 500)
Example request
curl "https://boatwork.co/api/v1/public/contractors/geo-search?lat=25.77&lng=-80.19&radius=20" \
  -H "Authorization: Bearer bw_public_your_key_here"
GET/api/v1/public/contractors/:slug

Returns a full public profile for a contractor by slug, including photos, videos, reviews, and badges.

Example request
curl "https://boatwork.co/api/v1/public/contractors/marine-engines-miami" \
  -H "Authorization: Bearer bw_public_your_key_here"
Example response
{
  "success": true,
  "data": {
    "id": "clt_abc123",
    "slug": "marine-engines-miami",
    "name": "Marine Engines Miami",
    "about": "Full-service marine engine repair and maintenance...",
    "tagline": "Certified outboard & inboard specialists",
    "phone": "+1-305-555-0100",
    "email": "info@marineenginesmiami.com",
    "location": "Miami, FL",
    "city": "Miami",
    "state": "FL",
    "logoUrl": "https://example.com/logo.jpg",
    "isVerified": true,
    "isClaimed": true,
    "rating": 4.8,
    "reviewCount": 142,
    "specialties": [
      { "id": "sp_1", "name": "Engine Repair", "slug": "engine-repair" }
    ],
    "photos": [],
    "videos": [],
    "reviews": [],
    "badges": ["Top Rated"],
    "social": {
      "facebook": null,
      "instagram": "https://instagram.com/marineenginesmiami",
      "linkedin": null,
      "youtube": null
    },
    "yearEstablished": 2015,
    "updatedAt": "2024-03-15T00:00:00.000Z"
  }
}
GET/api/v1/public/contractors/specialties

Returns all available specialty categories with their IDs and slugs. Use the slug value in search and geo-search filters.

Example request
curl "https://boatwork.co/api/v1/public/contractors/specialties" \
  -H "Authorization: Bearer bw_public_your_key_here"
Example response
{
  "success": true,
  "data": {
    "specialties": [
      { "id": "sp_1", "name": "Engine Repair", "slug": "engine-repair" },
      { "id": "sp_2", "name": "Yacht Detailing", "slug": "yacht-detailing" },
      { "id": "sp_3", "name": "Marine Electrical", "slug": "marine-electrical" }
    ]
  }
}

Error Responses

All errors return a consistent JSON shape with an HTTP status code.

Error format

Error response shape
{
  "success": false,
  "error": "string — machine-readable error code",
  "details": "string — human-readable explanation (when available)"
}
ParameterTypeDescription
400Bad RequestMissing or invalid query parameters (e.g. invalid lat/lng, unknown slug).
401UnauthorizedBearer token is missing, malformed, or has been revoked.
404Not FoundThe requested contractor slug or ID does not exist.
429Too Many RequestsDaily rate limit exceeded. Check the Retry-After header for seconds until reset.
500Server ErrorUnexpected internal error. If this persists, contact support@boatwork.co.
401 — invalid or missing key
{
  "success": false,
  "error": "Invalid or inactive API key"
}
404 — contractor not found
{
  "success": false,
  "error": "Contractor not found"
}
429 — rate limit exceeded
{
  "success": false,
  "error": "Daily rate limit of 500 requests exceeded"
}

429 responses include a Retry-After header with the number of seconds to wait before retrying.

Acceptable Use

By using the Boatwork API you agree to the following:

  • Use the API for lawful purposes only. Do not redistribute raw data in bulk or build a competing contractor directory.
  • Do not attempt to circumvent rate limits, scrape data beyond the pagination caps, or use automated tools to harvest contact information.
  • Attribute data to Boatwork when displaying contractor profiles or ratings publicly (e.g. "Data from Boatwork").
  • Keep your API key confidential. You are responsible for all activity under your key.
  • Boatwork reserves the right to revoke keys that violate these terms or negatively impact platform performance.

Full terms at boatwork.co/terms-of-use. Questions? Email support@boatwork.co.

Ready to build?

Get your API key from the developer console and start integrating the Boatwork contractor network into your application today.