{
  "openapi": "3.0.3",
  "info": {
    "title": "BeMyTalent — contact to draft quote",
    "version": "1.1.0",
    "description": "Documented subset of the REST API, not its full surface. Copy the API origin from Settings → Agents & API. Keys stay on your server. MCP has a separate OAuth contract."
  },
  "servers": [
    {
      "url": "https://{apiHost}/functions/v1",
      "variables": {
        "apiHost": {
          "default": "your-api-host.example.invalid",
          "description": "Host copied from the API address in BeMyTalent. This placeholder is not a live server."
        }
      }
    }
  ],
  "security": [
    {
      "BmtApiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "BmtApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A bmt_… key restricted to one project and the required scopes. Never a Supabase service key."
      }
    }
  },
  "paths": {
    "/crm-api/contacts": {
      "get": {
        "operationId": "findContact",
        "summary": "findContact",
        "description": "Exact, case-sensitive email match. Stop if several contacts match; this is not a uniqueness guarantee.",
        "x-bmt-required-scope": "crm:read",
        "parameters": [
          {
            "name": "filter.email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 1000
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response. A quote remains a draft.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "first_name": {
                            "type": "string"
                          },
                          "last_name": {
                            "type": "string"
                          },
                          "email": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id"
                        ]
                      }
                    },
                    "count": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "data",
                    "count"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Error. Reuse the same Idempotency-Key, credential, operation and JSON body after an uncertain response. Without that header, check the result before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createContact",
        "summary": "createContact",
        "description": "Create one contact in the key’s project. Optional Idempotency-Key prevents duplicate creation. The server fixes project_id; replay returns the same contact ID with its current fields.",
        "x-bmt-required-scope": "crm:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200,
              "pattern": "^[!-~]+$"
            },
            "description": "Generate one unique key per intended creation and persist it before calling. Reuse it only with the same JSON body, API credential, operation and project. JSON object field order does not matter. Different content or a deleted object returns HTTP 409. Keys do not expire automatically; project deletion removes receipts. Without this header, repeated calls remain separate creations."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "fr",
                      "de",
                      "it",
                      "en"
                    ]
                  }
                }
              },
              "example": {
                "first_name": "Alex",
                "last_name": "Integration Demo",
                "email": "integration-demo@example.invalid",
                "language": "fr"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful response. A quote remains a draft.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "first_name": {
                          "type": "string"
                        },
                        "last_name": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true when this is a replay; false on first creation.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "idempotency_conflict: same key with different content; creation_removed: the created object was deleted. No new creation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "enum": [
                        "idempotency_conflict",
                        "creation_removed"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. Reuse the same Idempotency-Key, credential, operation and JSON body after an uncertain response. Without that header, check the result before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/crm-api/contacts/{id}": {
      "get": {
        "operationId": "readContact",
        "summary": "readContact",
        "description": "Read back the contact in the key’s project.",
        "x-bmt-required-scope": "crm:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response. A quote remains a draft.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "first_name": {
                          "type": "string"
                        },
                        "last_name": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Error. Reuse the same Idempotency-Key, credential, operation and JSON body after an uncertain response. Without that header, check the result before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/accounting-api": {
      "post": {
        "operationId": "createQuote",
        "summary": "createQuote",
        "description": "Atomically create a draft quote and all its lines. Optional Idempotency-Key returns the original creation receipt on replay, even if the document has since changed. Read the document for its current state.",
        "x-bmt-required-scope": "invoicing:write",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "create_offer"
              ]
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200,
              "pattern": "^[!-~]+$"
            },
            "description": "Generate one unique key per intended creation and persist it before calling. Reuse it only with the same JSON body, API credential, operation and project. JSON object field order does not matter. Different content or a deleted object returns HTTP 409. Keys do not expire automatically; project deletion removes receipts. Without this header, repeated calls remain separate creations."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "contact_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "subject": {
                    "type": "string"
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "fr",
                      "de",
                      "it",
                      "en"
                    ]
                  },
                  "qr_bill_enabled": {
                    "type": "boolean"
                  },
                  "reminders_enabled": {
                    "type": "boolean"
                  },
                  "lines": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "properties": {
                        "description": {
                          "type": "string"
                        },
                        "quantity": {
                          "type": "number"
                        },
                        "unit": {
                          "type": "string"
                        },
                        "unit_price_excl_vat": {
                          "type": "number"
                        },
                        "vat_rate": {
                          "type": "number"
                        }
                      },
                      "required": [
                        "description",
                        "unit_price_excl_vat"
                      ]
                    }
                  }
                },
                "required": [
                  "contact_id",
                  "lines"
                ]
              },
              "example": {
                "subject": "INTEGRATION TEST — DO NOT SEND",
                "language": "fr",
                "qr_bill_enabled": false,
                "reminders_enabled": false,
                "lines": [
                  {
                    "description": "Demonstration service",
                    "quantity": 2,
                    "unit": "h",
                    "unit_price_excl_vat": 100
                  }
                ],
                "contact_id": "11111111-2222-4333-8444-555555555555"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response. A quote remains a draft.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "invoice_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "document_kind": {
                      "type": "string",
                      "enum": [
                        "quote"
                      ]
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "draft"
                      ]
                    },
                    "lines_count": {
                      "type": "integer"
                    },
                    "totals": {
                      "type": "object"
                    }
                  },
                  "required": [
                    "ok",
                    "invoice_id",
                    "document_kind",
                    "status"
                  ]
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true when this is a replay; false on first creation.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "idempotency_conflict: same key with different content; creation_removed: the created object was deleted. No new creation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "enum": [
                        "idempotency_conflict",
                        "creation_removed"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. Reuse the same Idempotency-Key, credential, operation and JSON body after an uncertain response. Without that header, check the result before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "readQuote",
        "summary": "readQuote",
        "description": "Read the quote and its lines by id. General lists are bounded and are not exhaustive.",
        "x-bmt-required-scope": "invoicing:read",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "quotes"
              ]
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response. A quote remains a draft.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "quotes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "contact_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "document_kind": {
                            "type": "string",
                            "enum": [
                              "quote"
                            ]
                          },
                          "status": {
                            "type": "string"
                          },
                          "total_incl_vat": {
                            "type": "number"
                          },
                          "lines": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          }
                        },
                        "required": [
                          "id",
                          "contact_id",
                          "document_kind",
                          "status",
                          "lines"
                        ]
                      }
                    },
                    "completeness": {
                      "type": "object",
                      "properties": {
                        "complete": {
                          "type": "boolean"
                        }
                      }
                    }
                  },
                  "required": [
                    "quotes",
                    "count"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Error. Reuse the same Idempotency-Key, credential, operation and JSON body after an uncertain response. Without that header, check the result before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
