> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.client-p.pylote.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Search freelancers (Stage 1, anonymized)

> Searches the Pylote freelancer pool, ranked by relevance by our matching
engine. Results are **anonymized**: partial profiles with no identifying
or contact data. The full profile is then obtained via
`POST /partners/reveal` with the `id` field.

**`keywords` semantics**:
- several words = implicit AND (`react node` = profiles matching both)
- `"design system"` = exact phrase
- `-wordpress` = exclusion
- OR is not supported at this stage

**Filters**: accepted values for `skills`, `workAreas` and `seniority`
come from the Pylote referential (`POST /referential`). `skills` is an
AND (the freelancer must have every requested skill), `workAreas` and
`seniority` are ORs.

Rate limit: 120 requests/minute per API key.




## OpenAPI

````yaml /openapi.yaml post /partners/search
openapi: 3.1.0
info:
  title: Pylote Client API
  version: 1.0.4
  description: >
    API de distribution des profils freelances Pylote.


    Permet aux clients (recruteurs, integrateurs, partenaires) de recuperer

    les freelances depuis la base Pylote, gerer les whitelist recruteurs

    et tracker les consultations de profils.


    Les profils sont retournes au format [JSON
    Resume](https://jsonresume.org/schema/)

    enrichi avec les metadonnees Pylote (disponibilite, TJM, mobilites,
    competences).


    ## Engagements clients


    En utilisant cette API, vous vous engagez a :

    1. **Tracker les consultations** de profils via `POST
    /partners/{slug}/events` (contractuel)

    2. **Supprimer les profils** dont le `status` est `deleted` de votre base

    3. **Ne jamais exposer** les emails personnels des freelances (utiliser les
    emails proxy Pylote)


    ## Protection des donnees


    Les donnees sont transformees avant distribution :

    - Les emails personnels sont remplaces par des **emails proxy**
    (`@freelance.pylote.io`)

    - Le champ `personalEmail` est un **hash SHA-256** (pour dedoublonnage,
    jamais l'email en clair)

    - Les URLs LinkedIn et CV passent par `hive.pylote.io` (tracking watermarke)

    - Les identifiants (`meta.id`) sont **chiffres** (AES-256-CBC) et opaques
  contact:
    name: Pylote
    url: https://pylote.io
    email: contact@pylote.io
servers:
  - url: https://client-p.pylote.io
    description: Production
  - url: https://client-pp.pylote.io
    description: Preprod
security:
  - apiKey: []
tags:
  - name: Freelances
    description: >
      Endpoints principaux pour recuperer les profils freelances.

      Les profils sont au format JSON Resume enrichi avec les metadonnees
      Pylote.
  - name: Partners
    description: >
      Endpoints pour les partenaires de distribution (ex: Agrega).

      Gestion de la whitelist recruteurs et **tracking obligatoire** des
      consultations de profils.
  - name: Integration
    description: |
      Endpoints pour les integrateurs (ex: BoondManager).
      Gestion des sous-clients et de leurs whitelist recruteurs.
  - name: Sandbox
    description: >
      Endpoints de test avec donnees anonymisees. Aucune cle API requise.

      Utilisez la sandbox pour valider votre integration avant de passer en
      production.
  - name: Admin
    description: >-
      Endpoints d'administration (cache, debug). Requiert un flag admin sur la
      cle API.
  - name: Health
    description: Health check de l'API et de ses dependances externes
paths:
  /partners/search:
    post:
      tags:
        - Partners
      summary: Search freelancers (Stage 1, anonymized)
      description: |
        Searches the Pylote freelancer pool, ranked by relevance by our matching
        engine. Results are **anonymized**: partial profiles with no identifying
        or contact data. The full profile is then obtained via
        `POST /partners/reveal` with the `id` field.

        **`keywords` semantics**:
        - several words = implicit AND (`react node` = profiles matching both)
        - `"design system"` = exact phrase
        - `-wordpress` = exclusion
        - OR is not supported at this stage

        **Filters**: accepted values for `skills`, `workAreas` and `seniority`
        come from the Pylote referential (`POST /referential`). `skills` is an
        AND (the freelancer must have every requested skill), `workAreas` and
        `seniority` are ORs.

        Rate limit: 120 requests/minute per API key.
      operationId: partnerSearch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                keywords:
                  type: string
                  description: Free-text query (max 500 characters)
                  example: react "design system" -wordpress
                skills:
                  type: array
                  maxItems: 20
                  description: >-
                    Required skills (AND). Use the `name` field from the
                    referential (Skills table).
                  items:
                    type: string
                  example:
                    - React
                    - TypeScript
                workAreas:
                  type: array
                  maxItems: 20
                  description: >-
                    Accepted mobility areas (OR). Use the `name` field from the
                    referential (Regions table).
                  items:
                    type: string
                  example:
                    - Île-de-France
                seniority:
                  type: array
                  maxItems: 10
                  description: >-
                    Accepted seniorities (OR). Use the `slug` field from the
                    referential (Seniority table).
                  items:
                    type: string
                  example:
                    - senior_6-10_ans
                    - master_10_ans
                available:
                  type: boolean
                  description: >-
                    If provided, filters on the freelancer's declared
                    availability
                page:
                  type: integer
                  minimum: 1
                  default: 1
                limit:
                  type: integer
                  minimum: 1
                  maximum: 100
                  default: 50
      responses:
        '200':
          description: Results ranked by relevance
          content:
            application/json:
              schema:
                type: object
                properties:
                  freelances:
                    type: array
                    items:
                      $ref: '#/components/schemas/RedactedFreelance'
                  infos:
                    type: object
                    properties:
                      total:
                        type: integer
                        example: 103
                      page:
                        type: integer
                        example: 1
                      limit:
                        type: integer
                        example: 50
                      totalPages:
                        type: integer
                        example: 3
        '400':
          description: Parametres invalides
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '401':
          description: Cle API manquante
        '403':
          description: Cle API invalide ou scope partenaire incorrect
        '429':
          description: Rate limit exceeded (120 requests/minute per API key)
components:
  schemas:
    RedactedFreelance:
      type: object
      description: |
        Redacted partial profile returned by the partner search (Stage 1).
        No identifying or contact data: no name, no email (even proxied), no
        phone, no profile links, no employer names.
        The full profile is obtained via `POST /partners/reveal` (Stage 2).
      properties:
        id:
          type: string
          format: uuid
          description: Unique freelance id, to be passed to `POST /partners/reveal`
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        headline:
          type: string
          example: Lead developpeuse React
        summary:
          type: string
          description: Profile summary, cleaned of emails and phone numbers
        location:
          type: object
          properties:
            city:
              type: string
              example: Paris
            region:
              type: string
              example: Île-de-France
            countryCode:
              type: string
              example: FR
            postalCode:
              type: string
              example: '75002'
        skills:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                example: React
              level:
                type: string
                example: Expert
              keywords:
                type: array
                items:
                  type: string
        languages:
          type: array
          items:
            type: object
            properties:
              language:
                type: string
                example: Français
              fluency:
                type: string
                example: Natif
        seniority:
          type: string
          description: Slug from the Seniority referential (list via `POST /referential`)
          example: senior_6-10_ans
        professions:
          type: array
          items:
            type: string
        availability:
          type: object
          properties:
            available:
              type: boolean
            availabilityDate:
              type: string
        preferences:
          type: object
          properties:
            remoteWork:
              type: array
              items:
                type: string
            missionDuration:
              type: array
              items:
                type: string
            daysPerWeek:
              type: array
              items:
                type: string
            workAreas:
              type: array
              description: >-
                Mobility areas, same format as `GET /freelances`
                (region/department/city/country)
              items:
                type: object
        workHistory:
          type: array
          description: >
            Work history. No employer field; descriptions are redacted (emails,

            phone numbers, URLs and the freelancer's own name removed). Free
            text

            written by the freelancer: a company name may occasionally appear.
          items:
            type: object
            properties:
              position:
                type: string
                example: Lead dev
              startDate:
                type: string
                example: '2021-01-01'
              endDate:
                type: string
                example: '2023-06-30'
              summary:
                type: string
                description: Mission description, redacted
                example: Refonte du design system, equipe de 6 devs.
        matchRank:
          type: integer
          description: >
            Absolute rank of the profile in the relevance ranking for this
            search

            (1 = best match). A real rank, not a percentage score.
          example: 12
        updatedAt:
          type: string
          description: Last profile update
    ValidationError:
      type: object
      properties:
        error:
          type: string
          example: Validation failed
        message:
          type: string
          example: '"modifiedTime" is required'
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >
        Cle API fournie par Pylote. Inclure dans le header `x-api-key` de chaque
        requete.


        Exemple : `x-api-key: votre-cle-api`

````