API Documentation

Quick, beginner-friendly guide for integrating with the SportFishTrader Broker Listing API using a single broker API key.

Broker Listing API

This API lets you create and manage your own SportFishTrader boat listings from your server using a single broker API key.

πŸ“Œ Key Features:

  • One broker key via x-api-key (or Authorization: Bearer ...)
  • Listings are always attributed to the key owner
  • Create supports a safe dryRun mode (no write)
  • Owner-only updates and mark-as-sold

Important: Use listingStatus to control validation strictness. Draft creates accept minimal fields; active/scheduled creates require complete details (photos, engines, location, etc.).

Authentication

Every request must include your broker API key. We recommend x-api-key; we also accept Authorization: Bearer <API_KEY>. API access is tied to your broker account and an active subscription.

Recommended headers: Send x-api-version: v1 on all requests. You can also send your own x-request-id (optional) and the API will echo it back as X-Request-Id. Include that request id when contacting support.

Idempotency: For POST /api/v1/create (non-dryRun), you can send x-idempotency-key to safely retry without double-creating.

Example Authentication Header

Terminal
curl -X GET https://www.sportfishtrader.com/api/v1/list?page=1&limit=25   -H "x-api-key: YOUR_BROKER_API_KEY_HERE" \
  -H "x-api-version: v1" \
  -H "x-request-id: YOUR_REQUEST_ID_OPTIONAL"

⚠️ Security Warning: Never expose your API key in client-side code or public repositories. Always keep it secure on your server.

API Builder

Use this tool to generate ready-to-copy request templates. It does not accept or test real keys (the examples always use YOUR_BROKER_API_KEY_HERE).

Endpoint
Create Mode
Options

Generated request: POST https://www.sportfishtrader.com/api/v1/create?dryRun=true

Templates

cURL
curl -X POST "https://www.sportfishtrader.com/api/v1/create?dryRun=true" \
  -H "x-api-key: YOUR_BROKER_API_KEY_HERE" \
  -H "x-api-version: v1" \
  -H "x-request-id: YOUR_REQUEST_ID_OPTIONAL" \
  -H "Content-Type: application/json" \
  -d '{
  "listingStatus": "draft",
  "year": 2018,
  "manufacturer": "Viking",
  "model": "52 Sport Tower"
}'
Node.js (fetch)
const res = await fetch('https://www.sportfishtrader.com/api/v1/create?dryRun=true', {
  method: 'POST',
  headers: {
    'x-api-key': 'YOUR_BROKER_API_KEY_HERE',
    'x-api-version': 'v1',
    'x-request-id': 'YOUR_REQUEST_ID_OPTIONAL',
    
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
  "listingStatus": "draft",
  "year": 2018,
  "manufacturer": "Viking",
  "model": "52 Sport Tower"
})
});

const data = await res.json();
console.log(data);
Python (requests)
import requests

url = "https://www.sportfishtrader.com/api/v1/create?dryRun=true"
headers = {
  "x-api-key": "YOUR_BROKER_API_KEY_HERE",
  "x-api-version": "v1",
  "x-request-id": "YOUR_REQUEST_ID_OPTIONAL",
  
  "Content-Type": "application/json"
}
payload = {
  "listingStatus": "draft",
  "year": 2018,
  "manufacturer": "Viking",
  "model": "52 Sport Tower"
}

res = requests.request("POST", url, json=payload, headers=headers)
print(res.status_code)
print(res.json())

Create Listing

Photos vs Media: Listings use top-level photos and featuredPhoto. The optional media object is used for videos and the media enhancement pipeline. You can omit media.photos; the API will mirror photos into it.

Broker listings only: Auction/marketplace and Voyage Photography fields are not part of the broker API contract.

POST

Create a new boat listing

/api/v1/create

Creates a new listing automatically attributed to your broker account. Use dryRun to validate without writing.

Request Headers

HeaderValueRequired
x-api-keyYour broker API key (YOUR_BROKER_API_KEY_HERE)Yes
x-api-versionv1Optional
x-request-idOptional client request idOptional
x-idempotency-keyOptional (create only; non-dryRun)Optional
Content-Typeapplication/jsonYes

Request Body

FieldTypeRequiredDescription
listingStatusstringOptionaldraft | active | live | scheduled
Example: draft
scheduledAtstring|DateOptionalOnly when listingStatus=scheduled (ISO timestamp)
Example: 2026-01-09T14:15:00-05:00
conditionstringOptionalNew | Used (required when publishing)
Example: Used
yearnumberYesYear
Example: 2018
manufacturerstringYesBuilder/manufacturer
Example: Viking
modelstringYesModel
Example: 52 Sport Tower
typestringOptionalBoat class/type (required when publishing)
Example: Sportfish
pricenumberOptionalRequired unless contactForPrice=true when publishing
Example: 1250000
contactForPricebooleanOptionalIf true, price can be omitted for publish
Example: false
locationCitystringOptionalCity
Example: Fort Lauderdale
locationStatestringOptionalState (required when publishing)
Example: FL
locationZIPstringOptionalZIP
Example: 33301
lengthnumberOptionalLength (feet; required when publishing)
Example: 52
beamstringOptionalBeam (feet)
Example: 16.5
draftstringOptionalDraft (feet)
Example: 4.5
cabinsstringOptionalCabins
Example: 2
headsstringOptionalHeads
Example: 2
capacitystringOptionalCapacity
Example: β€”
cruiseSpeedstringOptionalCruise speed
Example: β€”
maxSpeedstringOptionalMax speed
Example: β€”
holdingTankstringOptionalHolding tank
Example: β€”
waterTankstringOptionalWater tank
Example: β€”
descriptionstringOptionalDescription (>= 50 chars required when publishing)
photosarrayOptionalPhoto URLs (>= 1 required when publishing)
featuredPhotostringOptionalPrimary photo URL (defaults to photos[0])
mediaobjectOptionalMedia enhancement object (videos). Do not set media.photos.
isFeaturedbooleanOptionalFeatured listing flag
Example: false
engineTypestring|numberOptionalEngine count (1-6); may also be inferred from engineN fields
Example: 2
engineCountnumberOptionalOptional engine count (1-6); engineType is also accepted
Example: 2
engine{1..6}TypestringOptionalEngine type (required when publishing for each engine)
Example: Inboard
engine{1..6}MakestringOptionalEngine make (required when publishing for each engine)
Example: MAN
engine{1..6}ModelstringOptionalEngine model (required when publishing for each engine)
Example: V12
engine{1..6}PowernumberOptionalEngine power (required when publishing for each engine)
Example: 1550
engine{1..6}FuelTypestringOptionalEngine fuel type
Example: Diesel
engine{1..6}FuelTanknumberOptionalEngine fuel tank (gal)
Example: 0
engine{1..6}HoursnumberOptionalEngine hours
Example: 0
engine{1..6}YearnumberOptionalEngine year
Example: 0

Response Example

{
  "success": true,
  "id": "YOUR_NEW_LISTING_ID",
  "message": "Listing created successfully"
}

Dry Run (Recommended for Setup)

To validate your payload without creating a listing, append ?dryRun=true (or set header x-dry-run: true). The response will include normalizedData and ignoredFields.

Complete Field Template (Broker Listings)

This is a complete, copy/paste-ready broker listing payload template (no auctions / no reserve / no Voyage fields).

Full Create Payload Template
{
  "listingStatus": "active",
  "condition": "Used",
  "year": 2018,
  "manufacturer": "Viking",
  "model": "52 Sport Tower",
  "type": "Sportfish",
  "price": 1250000,
  "contactForPrice": false,
  "locationCity": "Fort Lauderdale",
  "locationState": "FL",
  "locationZIP": "33301",
  "length": 52,
  "beam": "16.5",
  "draft": "4.5",
  "cabins": "2",
  "heads": "2",
  "capacity": "β€”",
  "cruiseSpeed": "β€”",
  "maxSpeed": "β€”",
  "holdingTank": "β€”",
  "waterTank": "β€”",
  "engineType": "2",
  "engineCount": 2,
  "engine1Type": "Inboard",
  "engine1Make": "MAN",
  "engine1Model": "V12",
  "engine1Power": 1550,
  "engine1FuelType": "Diesel",
  "engine1FuelTank": 0,
  "engine1Hours": 0,
  "engine1Year": 0,
  "engine2Type": "Inboard",
  "engine2Make": "MAN",
  "engine2Model": "V12",
  "engine2Power": 1550,
  "engine2FuelType": "Diesel",
  "engine2FuelTank": 0,
  "engine2Hours": 0,
  "engine2Year": 0,
  "description": "Well-maintained, captain-kept, and tournament-ready. Recent service, clean engine room, and updated electronics. Call for full specs and showing availability.",
  "photos": [
    "https://example.com/photo-1.jpg",
    "https://example.com/photo-2.jpg"
  ],
  "featuredPhoto": "https://example.com/photo-1.jpg",
  "media": {
    "videos": {
      "longForm": [
        "https://example.com/video-long-1.mp4"
      ],
      "shortForm": [
        "https://example.com/video-short-1.mp4"
      ]
    }
  },
  "isFeatured": false
}

Update Listing

PUT

Update an existing listing

/api/v1/update/:listingId

Updates one or more fields of an existing listing you own.

Request Headers

HeaderValueRequired
x-api-keyYour broker API key (YOUR_BROKER_API_KEY_HERE)Yes
Content-Typeapplication/jsonYes

URL Parameters

ParameterDescription
listingIdThe unique ID of the listing to update

Request Body

FieldTypeRequiredDescription
pricenumberOptionalUpdated price
Example: 1199000
descriptionstringOptionalUpdated description
locationCitystringOptionalUpdated city
locationStatestringOptionalUpdated state
photosarrayOptionalReplace photos array with new URLs

Response Example

{
  "success": true,
  "message": "Listing updated successfully",
  "id": "YOUR_LISTING_ID"
}

List Active Listings

GET

List your active listings

/api/v1/list?page=1&limit=25

Returns paginated active listings where brokerId matches your API key owner. (Alias: /api/v1/get)

Request Headers

HeaderValueRequired
x-api-keyYour broker API key (YOUR_BROKER_API_KEY_HERE)Yes

URL Parameters

ParameterDescription
pagePage number (default 1)
limitItems per page (default 25, max 100)

Response Example

{
  "success": true,
  "listings": [
    {
      "id": "YOUR_LISTING_ID",
      "manufacturer": "Viking",
      "model": "52 Sport Tower",
      "year": 2018,
      "price": 1250000,
      "listingStatus": "active"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 25,
    "total": 1,
    "totalPages": 1,
    "hasNext": false,
    "hasPrev": false
  }
}

Mark As Sold

PATCH

Mark a listing as sold

/api/v1/sold/:listingId

Marks a listing you own as sold.

Request Headers

HeaderValueRequired
x-api-keyYour broker API key (YOUR_BROKER_API_KEY_HERE)Yes

URL Parameters

ParameterDescription
listingIdThe listing ID to mark as sold

Response Example

{ "id": "YOUR_LISTING_ID" }

Error Reference

Common errors you may encounter when using the Broker API:

Tip: Every response includes an X-Request-Id header. For debugging, log it and include it when contacting support.

Errors are returned as a structured JSON payload:

Example error payload
{
  "code": "RATE_001",
  "error": "Rate Limit Exceeded",
  "message": "You have exceeded your API rate limit of 300 requests.",
  "suggestion": "Your rate limit will reset at 2026-02-01T12:00:00.000Z. Consider implementing request queuing or caching to reduce API calls.",
  "requestId": "d3c6c6b9-0b7c-4e12-a5a2-...",
  "status": 429,
  "endpoint": "createListingApi",
  "method": "POST",
  "timestamp": "2026-02-01T11:14:53.000Z"
}

When rate limiting is enabled, responses also include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.

Missing API Key

Error Code: AUTH_001

Error Message: x-api-key header is required

Cause: Request was sent without the x-api-key header

Solution:

  • Include x-api-key header in all requests
  • Verify your API key is correctly configured
  • Check for typos in the header name

Invalid API Key

Error Code: AUTH_002

Error Message: The provided API key does not match any active broker subscription.

Cause: Key is incorrect, terminated, or the subscription is not active

Solution:

  • Verify you copied the correct API key for your broker account
  • Confirm your subscription status is active/trialing
  • Generate a new key in the Broker Portal if needed

API Disabled

Error Code: AUTH_005

Error Message: The API system is temporarily disabled by administrators.

Cause: Platform-level API setting is turned off

Solution:

  • Try again later
  • Contact SportFishTrader support if you need urgent access

Rate Limit Exceeded

Error Code: RATE_001

Error Message: You have exceeded your API rate limit.

Cause: Too many requests in the current rate limit window

Solution:

  • Retry after the reset time (see X-RateLimit-Reset)
  • Batch writes and avoid polling; use cursor pagination
  • Cache GET responses where possible
Back to Home