Developers
Build a BoatCloser connector
Connectors extend BoatCloser to the tools brokers already use — syncing listings to other marketplaces, or sending closing documents for e-signature. They’re built and operated by third-party developers and talk to BoatCloser through a single public REST API.
Overview
Everything happens over HTTPS against https://boatcloser.co/api/v1. A broker installs your connector from CRM → Connectors Marketplace; that authorises it with a scoped, per-brokerage access token. Your connector then reads and writes that brokerage’s data within the granted scopes, and can subscribe to webhooks to react to changes in real time.
Authentication
Every request carries a bearer token scoped to a single brokerage. Tokens come from the OAuth install flow (recommended) or are issued manually by a broker in CRM → Settings → API keys.
curl https://boatcloser.co/api/v1/listings \
-H "Authorization: Bearer bc_live_…"A token only ever accesses the brokerage it was issued for. Errors are JSON: { "error": { "code": "...", "message": "..." } } with 401 (missing/invalid key), 403 (missing scope), 404, and 422 (validation).
Scopes
A connector requests only the scopes it needs:
- Listing sync —
listings:read,listings:write - E-signature —
documents:read,documents:write - Messaging —
contacts:read,messages:read,messages:write - Scheduling —
appointments:read,appointments:write - Accounting —
accounting:read,accounting:write - Payments & escrow —
payments:read,payments:write
Install (OAuth 2.0 authorization code)
Register a connector app (name, developer, redirect URIs, requested scopes, optional install-time config fields). Send the broker to the authorize screen:
https://boatcloser.co/oauth/authorize
?client_id=<id>
&redirect_uri=<registered>
&scope=documents:read%20documents:write
&response_type=code
&state=<csrf>The broker approves; we redirect back with a code. Exchange it for an access token:
curl -X POST https://boatcloser.co/oauth/token \
-H "content-type: application/json" \
-d '{"grant_type":"authorization_code","code":"<code>",
"client_id":"<id>","client_secret":"<secret>","redirect_uri":"<registered>"}'
# -> { "access_token": "bc_tok_…", "token_type": "bearer", "scope": "documents:read documents:write" }If your connector declares install-time config (e.g. a broker-page URL), the broker enters it on the consent screen and you read it back from GET /api/v1/connection.
Listings API
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /listings | listings:read | List the brokerage's inventory |
| POST | /listings | listings:write | Create a listing |
| GET | /listings/:id | listings:read | Fetch one listing |
| PATCH | /listings/:id | listings:write | Partial update |
| DELETE | /listings/:id | listings:write | Remove a listing |
curl -X POST https://boatcloser.co/api/v1/listings \
-H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \
-d '{"make":"Beneteau","model":"Oceanis 46.1","year":2022,
"price":{"amountMinor":"38500000","currency":"EUR"},"status":"draft"}'Documents API (e-signature)
E-signature connectors operate on a brokerage’s contract documents — fetch the rendered document and its signers, then push signature status back.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /documents | documents:read | List documents (?status=SENT, ?dealId=…) |
| GET | /documents/:id | documents:read | Fetch one — incl. rendered content.html + signers |
| PATCH | /documents/:id | documents:write | Push back status / signed file / audit trail / envelope id / per-signer status |
A typical e-signature round-trip:
# 1. Receive a document.sent webhook, then fetch the document:
curl https://boatcloser.co/api/v1/documents/<id> -H "Authorization: Bearer $TOKEN"
# -> { ..., "content": { "html": "<h1>…</h1>" },
# "signers": [ { "id", "role", "name", "email", "order", "status" } ] }
# 2. Create your envelope from content.html (signers = recipients, routing = order),
# then record the envelope id:
curl -X PATCH https://boatcloser.co/api/v1/documents/<id> -H "Authorization: Bearer $TOKEN" \
-H "content-type: application/json" -d '{"esignEnvelopeId":"<your-envelope-id>"}'
# 3. On completion, push the result back:
curl -X PATCH https://boatcloser.co/api/v1/documents/<id> -H "Authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"status":"COMPLETED","signedFileUrl":"…","auditTrailUrl":"…",
"signers":[{"id":"<signerId>","status":"SIGNED"}]}'Messaging API (WhatsApp / SMS)
Messaging connectors let brokers reach clients on WhatsApp/SMS from the CRM and feed replies back onto the contact’s timeline.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /contacts | contacts:read | List contacts (name, phone, email) |
| GET | /contacts/:id | contacts:read | Fetch one contact |
| GET | /messages | messages:read | Message timeline (?contactId, ?dealId, ?channel) |
| POST | /messages | messages:write | Record a message — POST inbound client replies here |
# Inbound: when a client replies on WhatsApp, push it onto their timeline:
curl -X POST https://boatcloser.co/api/v1/messages -H "Authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"channel":"WHATSAPP","direction":"INBOUND","contactId":"<id>","body":"On my way"}'
# Outbound: subscribe to the message.outbound webhook (fired when a broker sends
# from a deal), read the contact's phone via GET /contacts/:id, and deliver via
# your WhatsApp Business / Twilio account.Scheduling API (calendar)
Scheduling connectors turn viewings & sea trials into calendar events and write the event back onto the appointment.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /appointments | appointments:read | List appointments (?status, ?dealId, ?from) |
| POST | /appointments | appointments:write | Create an appointment |
| GET | /appointments/:id | appointments:read | Fetch one — incl. contact + vessel |
| PATCH | /appointments/:id | appointments:write | Write back calendar event id / meeting URL / status |
# Subscribe to appointment.created, create the calendar event, then record it:
curl -X PATCH https://boatcloser.co/api/v1/appointments/<id> -H "Authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"status":"CONFIRMED","calendar":{"provider":"Cal.com","eventId":"…","meetingUrl":"…"}}'Accounting API (commission invoicing)
Accounting connectors raise the commission invoice when a deal closes. A “sale” is a Closed-Won deal with its sold price + parties.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /sales | accounting:read | Closed-Won sales (?uninvoiced=true for the queue) |
| GET | /sales/:id | accounting:read | One sale — sold price, parties, vessel |
| PATCH | /sales/:id | accounting:write | Write the raised invoice back onto the deal |
# Subscribe to deal.won, create the invoice in your accounting tool, then record it:
curl -X PATCH https://boatcloser.co/api/v1/sales/<id> -H "Authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"invoice":{"provider":"Xero","externalId":"INV-1042","url":"…","status":"DRAFT"}}'Payments API (deposits & escrow)
Payments connectors collect the buyer’s deposit (often held in escrow) for a deal. Statuses flow REQUESTED → PENDING → HELD → RELEASED (plus refunded/failed/cancelled).
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /payments | payments:read | Payments (?status=REQUESTED queue, ?dealId) |
| POST | /payments | payments:write | Create a payment request |
| GET | /payments/:id | payments:read | One payment |
| PATCH | /payments/:id | payments:write | Write back checkout link + status |
# Subscribe to payment.requested, create the checkout/escrow, then record it:
curl -X PATCH https://boatcloser.co/api/v1/payments/<id> -H "Authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"status":"PENDING","payment":{"provider":"Stripe","externalId":"cs_…","checkoutUrl":"…"}}'Webhooks
Register an endpoint in CRM → Settings → Webhooks. BoatCloser POSTs a signed JSON payload when a listing or document changes, so your connector can react without polling.
Events: listing.created, listing.updated, listing.deleted, document.created, document.sent, document.completed, message.outbound, appointment.created, appointment.updated, appointment.cancelled, deal.won, payment.requested, payment.updated.
POST <your endpoint>
headers: X-BoatCloser-Event, X-BoatCloser-Signature: sha256=<hmac>
{ "event": "document.sent",
"document": { "id": "…", "dealId": "…", "kind": "SALE_PURCHASE_AGREEMENT",
"status": "SENT", "name": "…" },
"at": "2026-06-05T08:00:00.000Z" }Verify each delivery: compute HMAC-SHA256(rawBody, signingSecret) and compare to the X-BoatCloser-Signature header. Delivery is best-effort with a short timeout.
Build & submit a connector
- Build your connector as a small service on your own infrastructure that calls the API above and (optionally) receives webhooks.
- Register your connector app and choose its category (listing sync or e-signature) and scopes.
- Test the install flow end-to-end against a brokerage you control.
- Submit it for listing in the Connectors Marketplace, including your developer agreement and per-connector terms (reviewed before listing).
Reference connectors live in the BoatCloser repo under connectors/ (a CSV sync, a YachtWorld importer, and a DocuSign e-signature connector). To get started or request developer access, get in touch at developers@boatcloser.co.