Documentation API publique Capt'n Boat

Documentation API publique Capt’n Boat

L’API publique Capt’n Boat permet de transmettre la création d’un besoin à l’équipe commerciale Capt’n Boat.

Pour cela, il vous faut :

  1. Créer un bateau
  2. Créer une annonce (mission)
  3. Créer un poste (Job)
  4. Renseigner les informations de facturation

L’équipe commerciale contactera ensuite votre client pour finaliser la réservation du Marin (Skipper / Hôtesse…) et lui enverra lien de paiement, facture et contrat par e‑mail.

Objectifs de l’API

L’API publique ouvre certaines fonctionnalités de la plateforme à des intégrations externes pour publier des annonces Capt’n Boat depuis votre propre infrastructure. Elle permet notamment de :

  • Enregistrer des navires
  • Créer des annonces pour ces navires (une annonce correspond à une mission et peut comprendre plusieurs postes)
  • Créer des fiches de poste (jobs)
  • Annuler une demande
  • Récupérer les informations de contact du marin retenu

L’API ne couvre pas la gestion complète des bateaux/annonces publiés : utilisez l’interface Capt’n Boat pour l’administration.

Implémentation technique

L’API externe est une API GraphQL. L’accès est restreint aux utilisateurs disposant d’un token fourni par Capt’n Boat.

  • Endpoint : https://api-int.captnboat.com/opengraphql
  • Authentification : header x-api-key: <VOTRE_TOKEN>
curl 'https://api-int.captnboat.com/opengraphql' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: <VOTRE_TOKEN>' \
  -d '{"query":"{ __typename }"}'
⚠️

Chaque requête doit inclure le header x-api-key.


Détail des requêtes disponibles

Lister les pavillons

Pour lier un navire à un pavillon.

query Flags {
  listFlags {
    nodes {
      id
      name
    }
  }
}

Exemple cURL

curl 'https://api-int.captnboat.com/opengraphql' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: <VOTRE_TOKEN>' \
  -d '{"query":"{listFlags{nodes{id name}}}"}'

Skipper correspondant

Pour estimer le nombre de skippers ayant les diplômes requis et disponibles sur une période donnée.

💡

Cette liste n’est pas la liste des candidats ayant postulé : ce sont des skippers éligibles (ils peuvent ne pas être intéressés ou demander une rémunération différente).

Query

query Correspondants {
  skipperCorrespondant(
    pAdType: DELIVERY
    pBoatCommercialUsage: false
    pBoatCountryId: "ef08f160-9858-464b-9e59-a93f94ad5260"
    pBoatType: SAILBOAT
    pCoastDistance: 25
    pCommercialActivity: false
    pStartHarborLatitude: 47.27991613225704
    pStartHarborLongitude: -2.1976906604134157
    pEndHarborLatitude: 47.27991613225704
    pEndHarborLongitude: -2.1976906604134157
    pBeam: 4.5
    pHullLength: 20
    pPassengerNumber: 10
    pIsCaptain: false
    pPosition: SKIPPER
    pStartDate: "2026-06-15"
    pEndDate: "2026-06-30"
  ) {
    totalCount
    nodes {
      firstName
      civility
      birthday
      nationality
      cv
      documents
      sailorAvatar
    }
  }
}

Payload (arguments)

  • pAdType: AdTypeEnum! — type de mission (DELIVERY, CHARTER, COACHING, …)
  • pBoatCommercialUsage: Boolean! — bateau exploité commercialement
  • pBoatCountryId: UUID! — pavillon/pays du bateau
  • pBoatType: BoatTypeEnum!MOTORBOAT | SAILBOAT | MULTIHULL
  • pCoastDistance: Int — distance max. à la côte (NM)
  • pCommercialActivity: Boolean! — activité commerciale pendant la mission
  • pStartHarborLatitude: Float!
  • pStartHarborLongitude: Float!
  • pEndHarborLatitude: Float!
  • pEndHarborLongitude: Float!
  • pBeam: Float! — largeur (m)
  • pHullLength: Float! — longueur de coque (m)
  • pPassengerNumber: Int!
  • pIsCaptain: Boolean! — besoin d’un capitaine (responsable légal)
  • pPosition: PositionEnum!SKIPPER, HOTESSE, …
  • pStartDate: Date!YYYY-MM-DD
  • pEndDate: Date!YYYY-MM-DD

Sélection & retour

  • totalCount: Int! — nombre total de skippers éligibles
  • nodes[].firstName: String
  • nodes[].civility: CivilityEnumMALE | FEMALE | …
  • nodes[].birthday: DateTime
  • nodes[].nationality: String
  • nodes[].averageNotations: Float Note
  • nodes[].cv: String — URL du CV
  • nodes[].documents: [String!]! — diplômes/certificats
  • nodes[].sailorAvatar: String — Photo

Exemple de résultat

{
  "data": {
    "skipperCorrespondant": {
      "totalCount": 1,
      "nodes": [
        {
          "firstName": "Charles",
          "civility": "MALE",
          "birthday": "1998-07-14T00:00:00Z",
          "nationality": "Française",
          "averageNotations": 4.2,
          "cv": "https://cellar-c2.services.clever-cloud.com/captn-int/b3qu09dl1_CV_pull1.PNG",
          "documents": [
            "BE VOILE",
            "CAPTAIN",
            "CFBS",
            "Human Safety & Social Responsibility Training (SPRS)",
            "GMDSS GOC / CGO",
            "MEDICAL VISIT"
          ],
          "sailorAvatar": "https://cellar-c2.services.clever-cloud.com/captn-dev/tthj05mz6_capitain_iglo.jpg"
        }
      ]
    }
  }
}

Enregistrer un navire

Créer (ou récupérer) un bateau. Si un bateau identique existe déjà, la mutation ne recrée pas l’entrée et renvoie uniquement son id.

mutation CreateBoat {
  createBoat(
    input: {
      name: "testBoat3"
      flagId: "ef08f160-9858-464b-9e59-a93f94ad5260"
      boatPictures: ["http://mypictures.com/myboat.jpg"]
      boatType: MOTORBOAT
      builderName: "Jo Boats"
      enginePower: 10
      hullLength: 15
      beam: 4
      hullType: MONOHULL
      modelName: "Jo Boat 1"
      registrationNumber: "registration"
      hasAutopilot: true
    }
  ) {
    boat { id }
  }
}

Payload (CreateBoatInput)

  • name: String!
  • flagId: UUID!
  • boatPictures: [String!]
  • boatType: BoatTypeEnum!MOTORBOAT | SAILBOAT | MULTIHULL
  • builderName: String!
  • enginePower: Int (HP)
  • hullLength: Float! (m)
  • beam: Float! (m)
  • hullType: HullTypeEnum!MONOHULL | CATAMARAN | TRIMARAN
  • modelName: String!
  • registrationNumber: String
  • hasAutopilot: Boolean

Résultat (exemple)

{
  "data": {
    "createBoat": { "boat": { "id": "b408c93b-74a7-4d67-9fdd-a61f764e2284" } }
  }
}

Créer une mission (Annonce)

Créer une mission (trajet + ports + dates) pour un bateau.

mutation CompleteAd {
  createCompleteAd(
    input: {
      adType: CHARTER
      boatId: "b408c93b-74a7-4d67-9fdd-a61f764e2284"
      startDate: "2025-06-01"
      endDate: "2025-06-15"
      spokenLanguage: ["245e9757-a9ab-4fd8-af33-f99498d5d3ef"]
      startHarborLatitude: 47.27991613225704
      startHarborLongitude: -2.1976906604134157
      endHarborLatitude: 47.27991613225704
      endHarborLongitude: -2.1976906604134157
      passengerNumber: 10
      commercialActivity: false
      description: "Une description"
    }
  ) {
    ad { id }
  }
}

Payload (CreateCompleteAdInput)

  • boatId: UUID!
  • startDate: DateTime! / endDate: DateTime!
  • startHarborLatitude: Float! / startHarborLongitude: Float!
  • endHarborLatitude: Float! / endHarborLongitude: Float!
  • adType: AdTypeEnum! — valeurs usuelles : CHARTER, COACHING, DELIVERY
  • passengerNumber: Int
  • description: String
  • commercialActivity: Boolean
  • spokenLanguage: [UUID]! — langues possibles :
query Languages {
  languages { nodes { id name } }
}

Résultat (exemple)

{
  "data": {
    "createCompleteAd": { "ad": { "id": "2c2bf016-5604-4e71-bf81-3a1e7399ee9d" } }
  }
}

Créer une fiche de poste (Job)

Estimation de rémunération

query Price {
  estimatedPrice(
    adType: CHARTER
    startDate: "2025-08-08"
    endDate: "2025-08-15"
    startHarborLatitude: 47.27991613225704
    startHarborLongitude: -2.1976906604134157
    endHarborLatitude: 47.27991613225704
    endHarborLongitude: -2.1976906604134157
    hullLength: 15
    positionType: SKIPPER
  )
}

Payload

  • startDate: Date! / endDate: Date!
  • startHarborLatitude/Longitude: Float!
  • endHarborLatitude/Longitude: Float!
  • adType: AdTypeEnum!CHARTER | SUPPORT | COACHING
  • hullLength: Float!
  • positionType: PositionEnum!SKIPPER, HOTESSE, MATELOT, SECOND, CHEF, MECANICIEN, CHEF_DE_QUART

Résultat (exemple)

{ "data": { "estimatedPrice": 2360 } }

Création du job

mutation CompleteJob {
  createCompleteJob(
    input: {
      adId: "20ca3ae7-a1c0-4bba-984f-0a9c952f7207"
      positionType: SKIPPER
      price: 2360
      travelFee: OWNER
      reserved: FAVOURITES
      referenceId: "12"
 
      billingFirstname: "Jo"
      billingLastname: "Durand"
      billingEmail: "billing@myemail.com"
      billingPhoneNumber: "1234567890"
      billingDateOfBirth: "2000-01-01"
      billingLanguage: "fr"
      billingSiret: "1234567890"
      billingRegistrationNumber: "ag-y78hn5"
 
      billingAddressFirstLine: "52 rue Truffaut"
      billingAddressZipCode: "75017"
      billingAddressCityName: "Paris"
      billingAddressCountry: "FR"
 
      lessor: ""
    }
  ) {
    job { id }
  }
}

Payload (CreateCompleteJobInput)

  • Références

    • adId: UUID!
    • referenceId: String — relier votre dossier interne au job Capt’n Boat
  • Poste

    • positionType: PositionEnum! — valeurs : SKIPPER, HOTESSE, MATELOT, SECOND, CHEF, MECANICIEN, CHEF_DE_QUART
    • price: Float!
    • travelFee: TravelFeeEnumOWNER | SKIPPER | NEGOCIABLE
    • reserved: ReservedEnumALL | APPROVED | FAVOURITES | RESERVED
  • Facturation (client)

    • billingFirstname: String!
    • billingLastname: String!
    • billingEmail: String!
    • billingPhoneNumber: String!
    • billingDateOfBirth: Date!
    • billingLanguage: String
    • billingRegistrationNumber: String!
    • billingSiret: String
    • billingAddressFirstLine: String!
    • billingAddressZipCode: String!
    • billingAddressCityName: String!
    • billingAddressCountry: String! (code ISO 2)
  • Divers

    • lessor: String

Résultat (exemple)

{
  "data": {
    "createCompleteJob": { "job": { "id": "636301f5-6c31-4d20-88c6-4eb8ddd81382" } }
  }
}

Annuler une demande (Job)

mutation CancelJob {
  cancelJob(
    input: {
      reason: DELAYED
      jobId: "636301f5-6c31-4d20-88c6-4eb8ddd81382"
      referenceId: "12"
    }
  ) {
    job { id }
  }
}

Payload (CancelJobInput)

  • reason: CancelReasonEnumFOUND, DELAYED, NOT_FOUND, ERROR, DUPLICATE, CONTACT, OTHER
  • jobId: UUID
  • referenceId: String

Résultat (exemple)

{
  "data": {
    "cancelJob": { "job": { "id": "636301f5-6c31-4d20-88c6-4eb8ddd81382" } }
  }
}

Offres des marins

Lister les offres reçues pour un job.

query Offres {
  jobOffers(
    jobId: "636301f5-6c31-4d20-88c6-4eb8ddd81382"
    referenceId: "12"
  ) {
    captnBoatProfil
    firstName
    isCaptnBoatApprooved
    isFavoris
    picture
    price
    travelFee
    urlSignature
  }
}

Arguments

  • jobId: UUID
  • referenceId: String

Résultat (exemple)

{
  "data": {
    "jobOffers": [
      {
        "captnBoatProfil": "https://captnboat.com/skippers/123",
        "firstName": "Marie",
        "isCaptnBoatApprooved": true,
        "isFavoris": false,
        "picture": "https://…/avatar.jpg",
        "price": 2450,
        "travelFee": 150,
        "urlSignature": "https://…/offer/123/sign"
      }
    ]
  }
}

Contact du marin

Disponible après paiement. Retourne les informations nécessaires à la contractualisation.

query Contact {
  sailorContact(
    jobId: "636301f5-6c31-4d20-88c6-4eb8ddd81382"
    referenceId: "12"
  ) {
    firstName
    lastName
    email
    phoneNumber
    civility
    birthday
    birthPlace
    birthCountry
    nationality
    price
    travelFee
    degree
    contract
    invoices
    address
  }
}

Arguments

  • jobId: UUID
  • referenceId: String

Champs retournés

  • firstName, lastName, email, phoneNumber: String
  • civility: CivilityEnum
  • birthday: DateTime
  • birthPlace, birthCountry: String
  • nationality: String
  • price, travelFee: Float
  • degree, contract: String
  • invoices: [String]
  • address: String

Résultat (exemple)

{
  "data": {
    "sailorContact": {
      "firstName": "",
      "lastName": "",
      "email": "",
      "phoneNumber": "",
      "civility": "",
      "birthday": "",
      "birthPlace": "",
      "birthCountry": "",
      "nationality": "",
      "price": 0,
      "travelFee": 0,
      "degree": "",
      "contract": "",
      "invoices": [],
      "address": ""
    }
  }
}

Note marin

Récupérer la note et le commentaire déposés par le client après la prestation.

query Notation {
  jobNotation(
    jobId: "636301f5-6c31-4d20-88c6-4eb8ddd81382"
    referenceId: "12"
  ) {
    notation
    comment
  }
}

Arguments

  • jobId: UUID
  • referenceId: String

Champs retournés

  • notation: Float (ou Int selon implémentation)
  • comment: String

Résultat (exemple)

{
  "data": {
    "jobNotation": {
      "notation": 4.8,
      "comment": "Très bon skipper, communication fluide."
    }
  }
}

Bonnes pratiques & validations

  • Coordonnées : utilisez Float pour latitude/longitude (pas de strings).
  • Dates : format ISO 8601 (YYYY-MM-DD / YYYY-MM-DDTHH:mm:ssZ).
  • Orthographe des champs : nationality (pas natinality), Latitude (un seul « t »), hasAutopilot (pas asAutopilot).
  • Idempotence : documentez les champs d’unicité de createBoat (ex. registrationNumber + flagId).
  • Pagination/tri : exposez idéalement first, offset, orderBy sur les listes (ex. skipperCorrespondant).

Pour toute demande supplémentaire : api-ext@captnboat.com.