{
  "openapi": "3.1.1",
  "info": {
    "title": "Rapport API",
    "version": "1.0.0",
    "summary": "Deterministic tools for people and AI agents.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://rapport.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "Catalog of all tools",
        "responses": {
          "200": {
            "description": "Tool list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{id}": {
      "get": {
        "operationId": "getTool",
        "summary": "Definition of one tool",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "rapport-vcard-convert",
                "rapport-pipeline-forecast",
                "rapport-csv-dedupe"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/rapport-vcard-convert/calculate": {
      "post": {
        "operationId": "calculateRapportVcardConvert",
        "summary": "Convert vCards (.vcf) to a contacts CSV and back: vCard 2.1, 3.0 and 4.0.",
        "description": "Turns a .vcf file with one or many contact cards into a clean CSV with first name, last name, e-mail, phone, company, job title, address and tags — or a contacts CSV (Rapport, HubSpot, Pipedrive, Outlook-style headers) into vCards. Folded lines, escaped commas and old QUOTED-PRINTABLE phone exports are handled. Same converter as Rapport’s vCard import and export.\n\nMethodology:\n- vCards are unfolded first (a line break followed by a space or tab continues the line), then split into properties; group prefixes (item1.EMAIL) are ignored and TYPE parameters choose the preferred e-mail, phone and address (PREF first, then work).\n- N gives last and first name; when it is missing, FN is split at the last space. ORG gives the company, ADR is joined into one address line (street, postal code + city, region, country). Values are unescaped (\\n, \\, and \\;). vCard 2.1 QUOTED-PRINTABLE values are decoded as UTF-8 (or Windows-1252 when the card says so).\n- CSV columns are recognised by their header names: Rapport’s own export, HubSpot and Pipedrive exports and common English and German names (Vorname, Nachname, Firma …). The CSV is RFC 4180 with comma, semicolon or tab.\n- vCards are written with CRLF line ends and folded at 75 octets without splitting a UTF-8 character; text is escaped. vCard 4.0 phones are written as tel: URIs.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "rapport_vcard_convert",
        "x-owner-app": "rapport",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RapportVcardConvertInput"
              },
              "examples": {
                "example1": {
                  "summary": "Three vCards (4.0, 3.0 with a folded note, 2.1 quoted-printable) to CSV",
                  "value": {
                    "text": "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Camille Rousseau\r\nN:Rousseau;Camille;;;\r\nORG:Atelier Rousseau SARL\r\nTITLE:Creative Director\r\nEMAIL;TYPE=work:camille@rousseau.example\r\nTEL;VALUE=uri;TYPE=work:tel:+33472000111\r\nADR;TYPE=work:;;12 rue de la République;Lyon;;69002;FR\r\nCATEGORIES:fashion,lead\r\nEND:VCARD\r\nBEGIN:VCARD\r\nVERSION:3.0\r\nFN:Tobias Krüger\r\nN:Krüger;Tobias;;;\r\nORG:Mediq Pharma Services\r\nTITLE:Communications Lead\r\nEMAIL;TYPE=INTERNET,WORK:tobias.krueger@mediq-pharma.example\r\nTEL;TYPE=CELL:+49 170 1234567\r\nNOTE:Met at the health-tech fair\\, interested in an intranet. Prefers calls in the\r\n morning.\r\nEND:VCARD\r\nBEGIN:VCARD\r\nVERSION:2.1\r\nN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:M=C3=BCller;J=C3=BCrgen;;;\r\nFN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:J=C3=BCrgen M=C3=BCller\r\nTEL;WORK;VOICE:+49 30 1234567\r\nEMAIL;INTERNET:juergen.mueller@example.org\r\nEND:VCARD\r\n"
                  }
                },
                "example2": {
                  "summary": "HubSpot contacts export to vCard 3.0",
                  "value": {
                    "text": "Record ID,First Name,Last Name,Email,Phone Number,Job Title,Company Name,Contact owner,Create Date,Last Activity Date,Marketing contact status,Legal basis for processing contact's data\r\n101,Lena,Vogt,lena.vogt@mediq.example,+49 89 7654321,Marketing Director,Mediq Health GmbH,Mara Lindqvist,2026-08-12 09:14,2026-11-20 15:02,Marketing contact,Freely given consent from contact\r\n102,Lena,Vogt,Lena.Vogt@mediq.example,,Marketing,Mediq Health,Jonas Becker,2026-11-03 11:40,,Non-marketing contact,\r\n103,Paul,Hansen,paul@hansen-kaffee.example,040 2345678,Owner,Kaffeerösterei Hansen,Jonas Becker,2025-12-01 10:00,2026-11-10 09:30,Non-marketing contact,Performance of a contract\r\n104,Paul,Hansen,,+49 40 2345678,Inhaber,Kaffeeroesterei Hansen,Jonas Becker,2026-02-14 16:20,,Non-marketing contact,\r\n105,Daan,de Vries,daan.devries@greenway.example,+31 10 555 0101,CIO,Greenway Logistics B.V.,Mara Lindqvist,2026-09-15 13:00,2026-11-18 10:15,Non-marketing contact,Legitimate interest – prospect/lead\r\n106,Sanne,Bakker,sanne.bakker@greenway.example,+31 10 555 0144,E-commerce Manager,Greenway Logistics B.V.,Ada Okafor,2026-09-20 08:45,2026-11-18 10:15,Marketing contact,Freely given consent from contact\r\n107,Sanne,Baker,s.bakker+events@greenway.example,,E-commerce,Greenway Logistics,Ada Okafor,2026-10-30 18:02,,Non-marketing contact,\r\n108,Ingrid,Halvorsen,ingrid.halvorsen@fjordline.example,+47 55 12 34 56,Head of Digital,Fjordline Ferries AS,Mara Lindqvist,2026-04-19 09:00,2026-11-21 14:00,Non-marketing contact,Legitimate interest – existing customer\r\n109,Yusuf,Demir,yusuf.demir@gmail.example,,Founder,,Ada Okafor,2026-11-07 20:11,,Marketing contact,Freely given consent from contact\r\n",
                    "version": "3.0"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RapportVcardConvertResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/rapport-pipeline-forecast/calculate": {
      "post": {
        "operationId": "calculateRapportPipelineForecast",
        "summary": "Weighted sales forecast, pipeline per stage, win rate and sales cycle from a deals CSV.",
        "description": "Reads a deals export (Rapport, HubSpot or Pipedrive CSV, or a Rapport CRM file) and computes the open pipeline per stage, the weighted forecast per month by expected close date, overdue deals, win rate by count and value, the average and median sales cycle and the numbers per owner. Same calculation as the Rapport dashboard.\n\nMethodology:\n- Weighted value of an open deal = value × probability. The probability is the deal’s own value when the file has one, otherwise the stage’s; won stages count 100 %, lost 0 %.\n- Forecast per month: open deals grouped by the month of their expected close date, starting with the month of “Today is”. Open deals whose expected close lies before “Today is” are listed as overdue instead; deals without a date are only in the stage totals.\n- Win rate = won ÷ (won + lost) among deals closed inside the window, by count and by value. Sales cycle = days from creation to the won date of the deals won in the window (average and median).\n- CSV files: stages are taken in the order they first appear among open deals. Without a probability column, stage probabilities are spread evenly (the tool says so), so add one for real numbers.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "rapport_pipeline_forecast",
        "x-owner-app": "rapport",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RapportPipelineForecastInput"
              },
              "examples": {
                "example1": {
                  "summary": "Pipedrive deals export, six months",
                  "value": {
                    "deals": "Deal - Title,Deal - Value,Deal - Currency,Deal - Pipeline,Deal - Stage,Deal - Status,Deal - Probability,Deal - Expected close date,Deal - Owner,Deal - Organization,Deal - Contact person,Deal - Deal created,Deal - Won time,Deal - Lost time,Deal - Lost reason\r\nBooking site relaunch,84000,EUR,Sales,Negotiation,open,75,2026-12-12,Mara Lindqvist,Fjordline Ferries AS,Ingrid Halvorsen,2026-09-15,,,\r\nOnline shop for beans,18500,EUR,Sales,Proposal made,open,50,2026-12-19,Jonas Becker,Kaffeerösterei Hansen,Paul Hansen,2026-10-15,,,\r\nPatient portal UX audit,12000,EUR,Sales,Qualified,open,25,2027-01-08,Ada Okafor,Mediq Health GmbH,Lena Vogt,2026-11-04,,,\r\nBrand refresh,9500,EUR,Sales,Lead in,open,10,2027-01-23,Jonas Becker,Atelier Rousseau SARL,Camille Rousseau,2026-11-09,,,\r\nDriver app design system,56000,EUR,Sales,Proposal made,open,60,2026-12-26,Mara Lindqvist,Greenway Logistics B.V.,Daan de Vries,2026-10-20,,,\r\nIntranet news hub,22000,EUR,Sales,Lead in,open,10,2027-02-07,Ada Okafor,Mediq Pharma Services,Tobias Krüger,2026-11-14,,,\r\nShop maintenance 2026,7200,EUR,Sales,Proposal made,won,,2026-08-21,Jonas Becker,Kaffeerösterei Hansen,Paul Hansen,2026-07-27,2026-08-21,,\r\nSpring campaign landing pages,14800,EUR,Sales,Negotiation,won,,2026-04-18,Mara Lindqvist,Solberg Outdoor,Elin Solberg,2026-03-09,2026-04-18,,\r\nAccessibility retrofit,31000,EUR,Sales,Negotiation,won,,2026-09-25,Ada Okafor,Mediq Health GmbH,Lena Vogt,2026-06-27,2026-09-25,,\r\nFleet tracking dashboard,42000,EUR,Sales,Proposal made,lost,,2026-07-17,Mara Lindqvist,Greenway Logistics B.V.,Daan de Vries,2026-05-08,,2026-07-17,Chose an in-house team\r\nOutdoor catalogue print,6000,EUR,Sales,Qualified,lost,,2026-03-09,Jonas Becker,Solberg Outdoor,Elin Solberg,2026-01-28,,2026-03-09,Budget cut\r\nFerry app onboarding,26000,EUR,Sales,Negotiation,won,,2026-11-04,Mara Lindqvist,Fjordline Ferries AS,Henrik Aas,2026-08-21,2026-11-04,,\r\n",
                    "asOf": "2026-11-24"
                  }
                },
                "example2": {
                  "summary": "Rapport agency template, twelve months",
                  "value": {
                    "deals": "{\"format\":\"rapport\",\"version\":1,\"name\":\"Northlight Studio — new business\",\"currency\":\"EUR\",\"country\":\"DE\",\"settings\":{\"privateDeals\":false,\"retentionMonths\":24,\"quotePrefix\":\"Q-\",\"nextQuote\":3,\"ossB2C\":true,\"quoteDays\":30,\"seller\":{\"name\":\"Northlight Studio GmbH\",\"address\":\"Kastanienallee 12, 10435 Berlin, Germany\",\"vatId\":\"DE123456789\",\"email\":\"hello@northlight.example\",\"phone\":\"\",\"iban\":\"DE02 1001 0010 0006 8201 01\"}},\"people\":[{\"id\":\"me\",\"name\":\"Mara Lindqvist\"},{\"id\":\"jon\",\"name\":\"Jonas Becker\"},{\"id\":\"ada\",\"name\":\"Ada Okafor\"}],\"pipelines\":[{\"id\":\"sales\",\"name\":\"Sales\",\"stages\":[{\"id\":\"lead\",\"name\":\"Lead\",\"probability\":10,\"kind\":\"open\"},{\"id\":\"qualified\",\"name\":\"Qualified\",\"probability\":25,\"kind\":\"open\"},{\"id\":\"proposal\",\"name\":\"Proposal\",\"probability\":50,\"kind\":\"open\"},{\"id\":\"negotiation\",\"name\":\"Negotiation\",\"probability\":75,\"kind\":\"open\"},{\"id\":\"won\",\"name\":\"Won\",\"probability\":100,\"kind\":\"won\"},{\"id\":\"lost\",\"name\":\"Lost\",\"probability\":0,\"kind\":\"lost\"}]}],\"companies\":[{\"id\":\"o1\",\"name\":\"Fjordline Ferries AS\",\"domain\":\"fjordline.example\",\"industry\":\"Travel\",\"size\":\"500–1000\",\"phone\":\"\",\"address\":\"Bergen, Norway\",\"country\":\"NO\",\"vatId\":\"\",\"owner\":\"me\",\"tags\":[\"enterprise\"],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-08T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"},{\"id\":\"o2\",\"name\":\"Kaffeerösterei Hansen\",\"domain\":\"hansen-kaffee.example\",\"industry\":\"Food \u0026 drink\",\"size\":\"10–50\",\"phone\":\"\",\"address\":\"Hamburg\",\"country\":\"DE\",\"vatId\":\"\",\"owner\":\"me\",\"tags\":[\"retail\"],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-09T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"},{\"id\":\"o3\",\"name\":\"Mediq Health GmbH\",\"domain\":\"mediq.example\",\"industry\":\"Healthcare\",\"size\":\"200–500\",\"phone\":\"\",\"address\":\"Munich\",\"country\":\"DE\",\"vatId\":\"DE811223344\",\"owner\":\"me\",\"tags\":[\"enterprise\",\"regulated\"],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-10T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"},{\"id\":\"o4\",\"name\":\"Atelier Rousseau SARL\",\"domain\":\"rousseau.example\",\"industry\":\"Fashion\",\"size\":\"10–50\",\"phone\":\"\",\"address\":\"Lyon, France\",\"country\":\"FR\",\"vatId\":\"FR40303265045\",\"owner\":\"me\",\"tags\":[],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-11T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"},{\"id\":\"o5\",\"name\":\"Greenway Logistics B.V.\",\"domain\":\"greenway.example\",\"industry\":\"Logistics\",\"size\":\"1000+\",\"phone\":\"\",\"address\":\"Rotterdam, Netherlands\",\"country\":\"NL\",\"vatId\":\"NL859052841B01\",\"owner\":\"me\",\"tags\":[\"enterprise\"],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-12T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"},{\"id\":\"o6\",\"name\":\"Mediq Pharma Services\",\"domain\":\"mediq-pharma.example\",\"industry\":\"Healthcare\",\"size\":\"50–200\",\"phone\":\"\",\"address\":\"Munich\",\"country\":\"DE\",\"vatId\":\"\",\"owner\":\"me\",\"tags\":[],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-13T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"},{\"id\":\"o7\",\"name\":\"Solberg Outdoor\",\"domain\":\"solberg.example\",\"industry\":\"Retail\",\"size\":\"50–200\",\"phone\":\"\",\"address\":\"Gothenburg, Sweden\",\"country\":\"SE\",\"vatId\":\"\",\"owner\":\"me\",\"tags\":[],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-14T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"},{\"id\":\"o8\",\"name\":\"Pixelwerk Freelancers\",\"domain\":\"pixelwerk.example\",\"industry\":\"Design\",\"size\":\"1–10\",\"phone\":\"\",\"address\":\"Leipzig\",\"country\":\"DE\",\"vatId\":\"\",\"owner\":\"me\",\"tags\":[\"partner\"],\"custom\":{},\"notes\":\"\",\"created\":\"2025-12-15T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\"}],\"contacts\":[{\"id\":\"c1\",\"firstName\":\"Ingrid\",\"lastName\":\"Halvorsen\",\"email\":\"ingrid.halvorsen@fjordline.example\",\"phone\":\"+47 55 12 34 56\",\"title\":\"Head of Digital\",\"companyId\":\"o1\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[\"decision-maker\"],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"legitimate-interest\",\"marketing\":false,\"date\":\"2026-04-28\",\"source\":\"First meeting\",\"note\":\"\"},\"created\":\"2026-04-28T10:00:00.000Z\",\"updated\":\"2026-11-21T10:00:00.000Z\",\"lastContact\":\"2026-11-21\"},{\"id\":\"c2\",\"firstName\":\"Paul\",\"lastName\":\"Hansen\",\"email\":\"paul.hansen@hansen-kaffee.example\",\"phone\":\"+49 40 2345678\",\"title\":\"Owner\",\"companyId\":\"o2\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[\"customer\",\"decision-maker\"],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"contract\",\"marketing\":false,\"date\":\"2025-12-29\",\"source\":\"First meeting\",\"note\":\"\"},\"created\":\"2025-12-29T10:00:00.000Z\",\"updated\":\"2026-11-12T10:00:00.000Z\",\"lastContact\":\"2026-11-12\"},{\"id\":\"c3\",\"firstName\":\"Lena\",\"lastName\":\"Vogt\",\"email\":\"lena.vogt@mediq.example\",\"phone\":\"+49 89 7654321\",\"title\":\"Marketing Director\",\"companyId\":\"o3\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[\"decision-maker\"],\"custom\":{\"cf2\":true},\"notes\":\"\",\"consent\":{\"basis\":\"consent\",\"marketing\":true,\"date\":\"2026-08-26\",\"source\":\"Web form\",\"note\":\"\"},\"created\":\"2026-08-26T10:00:00.000Z\",\"updated\":\"2026-11-23T10:00:00.000Z\",\"lastContact\":\"2026-11-23\"},{\"id\":\"c4\",\"firstName\":\"Camille\",\"lastName\":\"Rousseau\",\"email\":\"camille.rousseau@rousseau.example\",\"phone\":\"\",\"title\":\"Creative Director\",\"companyId\":\"o4\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"legitimate-interest\",\"marketing\":false,\"date\":\"2026-06-27\",\"source\":\"First meeting\",\"note\":\"\"},\"created\":\"2026-06-27T10:00:00.000Z\",\"updated\":\"2026-10-15T10:00:00.000Z\",\"lastContact\":\"2026-10-15\"},{\"id\":\"c5\",\"firstName\":\"Daan\",\"lastName\":\"de Vries\",\"email\":\"daan.devries@greenway.example\",\"phone\":\"\",\"title\":\"CIO\",\"companyId\":\"o5\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[\"decision-maker\"],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"legitimate-interest\",\"marketing\":false,\"date\":\"2026-09-25\",\"source\":\"First meeting\",\"note\":\"\"},\"created\":\"2026-09-25T10:00:00.000Z\",\"updated\":\"2026-11-18T10:00:00.000Z\",\"lastContact\":\"2026-11-18\"},{\"id\":\"c6\",\"firstName\":\"Sanne\",\"lastName\":\"Bakker\",\"email\":\"sanne.bakker@greenway.example\",\"phone\":\"\",\"title\":\"E-commerce Manager\",\"companyId\":\"o5\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[],\"custom\":{\"cf2\":true},\"notes\":\"\",\"consent\":{\"basis\":\"consent\",\"marketing\":true,\"date\":\"2026-09-30\",\"source\":\"Web form\",\"note\":\"\"},\"created\":\"2026-09-30T10:00:00.000Z\",\"updated\":\"2026-11-18T10:00:00.000Z\",\"lastContact\":\"2026-11-18\"},{\"id\":\"c7\",\"firstName\":\"Tobias\",\"lastName\":\"Krüger\",\"email\":\"tobias.kruger@mediq-pharma.example\",\"phone\":\"\",\"title\":\"Communications Lead\",\"companyId\":\"o6\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"legitimate-interest\",\"marketing\":false,\"date\":\"2026-10-25\",\"source\":\"First meeting\",\"note\":\"\"},\"created\":\"2026-10-25T10:00:00.000Z\",\"updated\":\"2026-11-09T10:00:00.000Z\",\"lastContact\":\"2026-11-09\"},{\"id\":\"c8\",\"firstName\":\"Elin\",\"lastName\":\"Solberg\",\"email\":\"elin.solberg@solberg.example\",\"phone\":\"\",\"title\":\"CEO\",\"companyId\":\"o7\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[\"customer\"],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"contract\",\"marketing\":false,\"date\":\"2025-09-30\",\"source\":\"First meeting\",\"note\":\"\"},\"created\":\"2025-09-30T10:00:00.000Z\",\"updated\":\"2025-11-09T10:00:00.000Z\",\"lastContact\":\"2025-11-09\"},{\"id\":\"c9\",\"firstName\":\"Max\",\"lastName\":\"Pfeiffer\",\"email\":\"max.pfeiffer@pixelwerk.example\",\"phone\":\"\",\"title\":\"Freelance developer\",\"companyId\":\"o8\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[\"partner\"],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"contract\",\"marketing\":false,\"date\":\"2025-07-12\",\"source\":\"First meeting\",\"note\":\"\"},\"created\":\"2025-07-12T10:00:00.000Z\",\"updated\":\"2026-10-30T10:00:00.000Z\",\"lastContact\":\"2026-10-30\"},{\"id\":\"c10\",\"firstName\":\"Lena\",\"lastName\":\"Vogt\",\"email\":\"lena.vogt@mediq.example\",\"phone\":\"\",\"title\":\"Marketing\",\"companyId\":\"o3\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"\",\"marketing\":false,\"date\":\"\",\"source\":\"\",\"note\":\"\"},\"created\":\"2026-11-12T10:00:00.000Z\",\"updated\":\"2026-11-14T10:00:00.000Z\",\"lastContact\":\"\"},{\"id\":\"c11\",\"firstName\":\"Henrik\",\"lastName\":\"Aas\",\"email\":\"henrik.aas@fjordline.example\",\"phone\":\"\",\"title\":\"Product Owner\",\"companyId\":\"o1\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"consent\",\"marketing\":false,\"date\":\"2026-10-10\",\"source\":\"Web form\",\"note\":\"\"},\"created\":\"2026-10-10T10:00:00.000Z\",\"updated\":\"2026-11-15T10:00:00.000Z\",\"lastContact\":\"2026-11-15\"},{\"id\":\"c12\",\"firstName\":\"Yusuf\",\"lastName\":\"Demir\",\"email\":\"yusuf.demir@example.org\",\"phone\":\"\",\"title\":\"Founder\",\"companyId\":\"\",\"owner\":\"me\",\"address\":\"\",\"country\":\"\",\"birthday\":\"\",\"website\":\"\",\"tags\":[\"lead\"],\"custom\":{},\"notes\":\"\",\"consent\":{\"basis\":\"consent\",\"marketing\":true,\"date\":\"2026-11-16\",\"source\":\"Web form\",\"note\":\"\"},\"created\":\"2026-11-16T10:00:00.000Z\",\"updated\":\"2026-11-14T10:00:00.000Z\",\"lastContact\":\"\"}],\"relationships\":[{\"id\":\"r1\",\"from\":\"o:o3\",\"to\":\"o:o6\",\"type\":\"parent-of\",\"note\":\"\"},{\"id\":\"r2\",\"from\":\"o:o8\",\"to\":\"o:o2\",\"type\":\"partner\",\"note\":\"\"},{\"id\":\"r3\",\"from\":\"c:c6\",\"to\":\"c:c5\",\"type\":\"reports-to\",\"note\":\"\"},{\"id\":\"r4\",\"from\":\"c:c11\",\"to\":\"c:c1\",\"type\":\"referred-by\",\"note\":\"\"}],\"deals\":[{\"id\":\"d1\",\"title\":\"Booking site relaunch\",\"pipelineId\":\"sales\",\"stageId\":\"negotiation\",\"value\":84000,\"probability\":null,\"expectedClose\":\"2026-12-12\",\"owner\":\"me\",\"companyId\":\"o1\",\"contactIds\":[\"c1\",\"c11\"],\"tags\":[\"web\"],\"custom\":{\"cf1\":\"Referral\"},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-09-15T10:00:00.000Z\",\"updated\":\"2026-11-24T10:00:00.000Z\",\"closedAt\":\"\",\"history\":[{\"at\":\"2026-09-15T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-10-08T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-11-01T10:00:00.000Z\",\"stageId\":\"proposal\"},{\"at\":\"2026-11-24T10:00:00.000Z\",\"stageId\":\"negotiation\"}]},{\"id\":\"d2\",\"title\":\"Online shop for beans and subscriptions\",\"pipelineId\":\"sales\",\"stageId\":\"proposal\",\"value\":18500,\"probability\":null,\"expectedClose\":\"2026-12-19\",\"owner\":\"jon\",\"companyId\":\"o2\",\"contactIds\":[\"c2\"],\"tags\":[\"shop\"],\"custom\":{\"cf1\":\"Website\"},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-10-15T10:00:00.000Z\",\"updated\":\"2026-11-24T10:00:00.000Z\",\"closedAt\":\"\",\"history\":[{\"at\":\"2026-10-15T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-11-04T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-11-24T10:00:00.000Z\",\"stageId\":\"proposal\"}]},{\"id\":\"d3\",\"title\":\"Patient portal UX audit\",\"pipelineId\":\"sales\",\"stageId\":\"qualified\",\"value\":12000,\"probability\":null,\"expectedClose\":\"2027-01-08\",\"owner\":\"ada\",\"companyId\":\"o3\",\"contactIds\":[\"c3\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-11-04T10:00:00.000Z\",\"updated\":\"2026-11-24T10:00:00.000Z\",\"closedAt\":\"\",\"history\":[{\"at\":\"2026-11-04T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-11-24T10:00:00.000Z\",\"stageId\":\"qualified\"}]},{\"id\":\"d4\",\"title\":\"Brand refresh and lookbook\",\"pipelineId\":\"sales\",\"stageId\":\"lead\",\"value\":9500,\"probability\":null,\"expectedClose\":\"2027-01-23\",\"owner\":\"jon\",\"companyId\":\"o4\",\"contactIds\":[\"c4\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-11-09T10:00:00.000Z\",\"updated\":\"2026-11-24T10:00:00.000Z\",\"closedAt\":\"\",\"history\":[{\"at\":\"2026-11-09T10:00:00.000Z\",\"stageId\":\"lead\"}]},{\"id\":\"d5\",\"title\":\"Driver app design system\",\"pipelineId\":\"sales\",\"stageId\":\"proposal\",\"value\":56000,\"probability\":60,\"expectedClose\":\"2026-12-26\",\"owner\":\"me\",\"companyId\":\"o5\",\"contactIds\":[\"c5\",\"c6\"],\"tags\":[],\"custom\":{\"cf1\":\"Event\"},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-10-20T10:00:00.000Z\",\"updated\":\"2026-11-24T10:00:00.000Z\",\"closedAt\":\"\",\"history\":[{\"at\":\"2026-10-20T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-11-07T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-11-24T10:00:00.000Z\",\"stageId\":\"proposal\"}]},{\"id\":\"d6\",\"title\":\"Intranet news hub\",\"pipelineId\":\"sales\",\"stageId\":\"lead\",\"value\":22000,\"probability\":null,\"expectedClose\":\"2027-02-07\",\"owner\":\"ada\",\"companyId\":\"o6\",\"contactIds\":[\"c7\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-11-14T10:00:00.000Z\",\"updated\":\"2026-11-24T10:00:00.000Z\",\"closedAt\":\"\",\"history\":[{\"at\":\"2026-11-14T10:00:00.000Z\",\"stageId\":\"lead\"}]},{\"id\":\"d7\",\"title\":\"Shop maintenance 2026\",\"pipelineId\":\"sales\",\"stageId\":\"won\",\"value\":7200,\"probability\":null,\"expectedClose\":\"2026-08-21\",\"owner\":\"jon\",\"companyId\":\"o2\",\"contactIds\":[\"c2\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-07-27T10:00:00.000Z\",\"updated\":\"2026-08-21T10:00:00.000Z\",\"closedAt\":\"2026-08-21T16:00:00.000Z\",\"history\":[{\"at\":\"2026-07-27T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-08-04T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-08-13T10:00:00.000Z\",\"stageId\":\"proposal\"},{\"at\":\"2026-08-21T10:00:00.000Z\",\"stageId\":\"won\"}]},{\"id\":\"d8\",\"title\":\"Spring campaign landing pages\",\"pipelineId\":\"sales\",\"stageId\":\"won\",\"value\":14800,\"probability\":null,\"expectedClose\":\"2026-04-18\",\"owner\":\"me\",\"companyId\":\"o7\",\"contactIds\":[\"c8\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-03-09T10:00:00.000Z\",\"updated\":\"2026-04-18T10:00:00.000Z\",\"closedAt\":\"2026-04-18T16:00:00.000Z\",\"history\":[{\"at\":\"2026-03-09T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-03-22T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-04-05T10:00:00.000Z\",\"stageId\":\"proposal\"},{\"at\":\"2026-04-18T10:00:00.000Z\",\"stageId\":\"won\"}]},{\"id\":\"d9\",\"title\":\"Accessibility retrofit\",\"pipelineId\":\"sales\",\"stageId\":\"won\",\"value\":31000,\"probability\":null,\"expectedClose\":\"2026-09-25\",\"owner\":\"ada\",\"companyId\":\"o3\",\"contactIds\":[\"c3\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-06-27T10:00:00.000Z\",\"updated\":\"2026-09-25T10:00:00.000Z\",\"closedAt\":\"2026-09-25T16:00:00.000Z\",\"history\":[{\"at\":\"2026-06-27T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-07-27T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-08-26T10:00:00.000Z\",\"stageId\":\"proposal\"},{\"at\":\"2026-09-25T10:00:00.000Z\",\"stageId\":\"won\"}]},{\"id\":\"d10\",\"title\":\"Fleet tracking dashboard\",\"pipelineId\":\"sales\",\"stageId\":\"lost\",\"value\":42000,\"probability\":null,\"expectedClose\":\"2026-07-17\",\"owner\":\"me\",\"companyId\":\"o5\",\"contactIds\":[\"c5\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"Chose an in-house team\",\"created\":\"2026-05-08T10:00:00.000Z\",\"updated\":\"2026-07-17T10:00:00.000Z\",\"closedAt\":\"2026-07-17T16:00:00.000Z\",\"history\":[{\"at\":\"2026-05-08T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-05-31T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-06-24T10:00:00.000Z\",\"stageId\":\"proposal\"},{\"at\":\"2026-07-17T10:00:00.000Z\",\"stageId\":\"lost\"}]},{\"id\":\"d11\",\"title\":\"Outdoor catalogue print\",\"pipelineId\":\"sales\",\"stageId\":\"lost\",\"value\":6000,\"probability\":null,\"expectedClose\":\"2026-03-19\",\"owner\":\"jon\",\"companyId\":\"o7\",\"contactIds\":[\"c8\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"Budget cut\",\"created\":\"2026-01-28T10:00:00.000Z\",\"updated\":\"2026-03-19T10:00:00.000Z\",\"closedAt\":\"2026-03-19T16:00:00.000Z\",\"history\":[{\"at\":\"2026-01-28T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-02-14T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-03-02T10:00:00.000Z\",\"stageId\":\"proposal\"},{\"at\":\"2026-03-19T10:00:00.000Z\",\"stageId\":\"lost\"}]},{\"id\":\"d12\",\"title\":\"Concept workshop\",\"pipelineId\":\"sales\",\"stageId\":\"qualified\",\"value\":3500,\"probability\":null,\"expectedClose\":\"2026-12-06\",\"owner\":\"ada\",\"companyId\":\"\",\"contactIds\":[\"c12\"],\"tags\":[],\"custom\":{\"cf1\":\"Website\"},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-11-18T10:00:00.000Z\",\"updated\":\"2026-11-24T10:00:00.000Z\",\"closedAt\":\"\",\"history\":[{\"at\":\"2026-11-18T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-11-24T10:00:00.000Z\",\"stageId\":\"qualified\"}]},{\"id\":\"d13\",\"title\":\"Ferry app onboarding\",\"pipelineId\":\"sales\",\"stageId\":\"won\",\"value\":26000,\"probability\":null,\"expectedClose\":\"2026-11-04\",\"owner\":\"me\",\"companyId\":\"o1\",\"contactIds\":[\"c11\"],\"tags\":[],\"custom\":{},\"notes\":\"\",\"lostReason\":\"\",\"created\":\"2026-08-21T10:00:00.000Z\",\"updated\":\"2026-11-04T10:00:00.000Z\",\"closedAt\":\"2026-11-04T16:00:00.000Z\",\"history\":[{\"at\":\"2026-08-21T10:00:00.000Z\",\"stageId\":\"lead\"},{\"at\":\"2026-09-15T10:00:00.000Z\",\"stageId\":\"qualified\"},{\"at\":\"2026-10-10T10:00:00.000Z\",\"stageId\":\"proposal\"},{\"at\":\"2026-11-04T10:00:00.000Z\",\"stageId\":\"won\"}]}],\"activities\":[{\"id\":\"a1\",\"type\":\"call\",\"subject\":\"Discuss scope options with Ingrid\",\"body\":\"\",\"due\":\"2026-11-23T14:00\",\"done\":false,\"doneAt\":\"\",\"owner\":\"me\",\"contactId\":\"c1\",\"companyId\":\"\",\"dealId\":\"d1\",\"remindMinutes\":30,\"created\":\"2026-11-21T10:00:00.000Z\"},{\"id\":\"a2\",\"type\":\"meeting\",\"subject\":\"Negotiation meeting in Bergen (video)\",\"body\":\"\",\"due\":\"2026-11-27T10:30\",\"done\":false,\"doneAt\":\"\",\"owner\":\"me\",\"contactId\":\"c1\",\"companyId\":\"\",\"dealId\":\"d1\",\"remindMinutes\":30,\"created\":\"2026-11-22T10:00:00.000Z\"},{\"id\":\"a3\",\"type\":\"task\",\"subject\":\"Send revised proposal to Paul\",\"body\":\"\",\"due\":\"2026-11-24\",\"done\":false,\"doneAt\":\"\",\"owner\":\"jon\",\"contactId\":\"c2\",\"companyId\":\"\",\"dealId\":\"d2\",\"remindMinutes\":-1,\"created\":\"2026-11-22T10:00:00.000Z\"},{\"id\":\"a4\",\"type\":\"email\",\"subject\":\"Proposal sent\",\"body\":\"\",\"due\":\"2026-11-12\",\"done\":true,\"doneAt\":\"2026-11-12T11:00:00.000Z\",\"owner\":\"jon\",\"contactId\":\"c2\",\"companyId\":\"\",\"dealId\":\"d2\",\"remindMinutes\":-1,\"created\":\"2026-11-10T10:00:00.000Z\"},{\"id\":\"a5\",\"type\":\"meeting\",\"subject\":\"Discovery workshop with the marketing team\",\"body\":\"\",\"due\":\"2026-11-16T09:00\",\"done\":true,\"doneAt\":\"2026-11-16T09:00:00.000Z\",\"owner\":\"ada\",\"contactId\":\"c3\",\"companyId\":\"\",\"dealId\":\"d3\",\"remindMinutes\":30,\"created\":\"2026-11-14T10:00:00.000Z\"},{\"id\":\"a6\",\"type\":\"task\",\"subject\":\"Prepare audit plan\",\"body\":\"\",\"due\":\"2026-11-29\",\"done\":false,\"doneAt\":\"\",\"owner\":\"ada\",\"contactId\":\"c3\",\"companyId\":\"\",\"dealId\":\"d3\",\"remindMinutes\":-1,\"created\":\"2026-11-22T10:00:00.000Z\"},{\"id\":\"a7\",\"type\":\"call\",\"subject\":\"Intro call\",\"body\":\"\",\"due\":\"2026-11-20\",\"done\":true,\"doneAt\":\"2026-11-20T11:00:00.000Z\",\"owner\":\"jon\",\"contactId\":\"c4\",\"companyId\":\"\",\"dealId\":\"d4\",\"remindMinutes\":-1,\"created\":\"2026-11-18T10:00:00.000Z\"},{\"id\":\"a8\",\"type\":\"call\",\"subject\":\"Follow up on the design system proposal\",\"body\":\"\",\"due\":\"2026-11-21\",\"done\":false,\"doneAt\":\"\",\"owner\":\"me\",\"contactId\":\"c5\",\"companyId\":\"\",\"dealId\":\"d5\",\"remindMinutes\":-1,\"created\":\"2026-11-19T10:00:00.000Z\"},{\"id\":\"a9\",\"type\":\"note\",\"subject\":\"Budget approved for Q1\",\"body\":\"Sanne confirmed that the budget is approved; the board wants a pilot with one driver team first.\",\"due\":\"\",\"done\":true,\"doneAt\":\"2026-11-18T11:00:00.000Z\",\"owner\":\"me\",\"contactId\":\"c6\",\"companyId\":\"\",\"dealId\":\"d5\",\"remindMinutes\":-1,\"created\":\"2026-11-16T10:00:00.000Z\"},{\"id\":\"a10\",\"type\":\"task\",\"subject\":\"Check references for the intranet project\",\"body\":\"\",\"due\":\"2026-12-03\",\"done\":false,\"doneAt\":\"\",\"owner\":\"ada\",\"contactId\":\"c7\",\"companyId\":\"\",\"dealId\":\"d6\",\"remindMinutes\":-1,\"created\":\"2026-11-22T10:00:00.000Z\"},{\"id\":\"a11\",\"type\":\"call\",\"subject\":\"Yearly check-in with Elin\",\"body\":\"\",\"due\":\"2025-11-19\",\"done\":true,\"doneAt\":\"2025-11-19T11:00:00.000Z\",\"owner\":\"me\",\"contactId\":\"c8\",\"companyId\":\"\",\"dealId\":\"\",\"remindMinutes\":-1,\"created\":\"2025-11-17T10:00:00.000Z\"},{\"id\":\"a12\",\"type\":\"meeting\",\"subject\":\"Partner lunch\",\"body\":\"\",\"due\":\"2026-10-30\",\"done\":true,\"doneAt\":\"2026-10-30T11:00:00.000Z\",\"owner\":\"jon\",\"contactId\":\"c9\",\"companyId\":\"o8\",\"dealId\":\"\",\"remindMinutes\":-1,\"created\":\"2026-10-28T10:00:00.000Z\"},{\"id\":\"a13\",\"type\":\"task\",\"subject\":\"Book the concept workshop room\",\"body\":\"\",\"due\":\"2026-11-26\",\"done\":false,\"doneAt\":\"\",\"owner\":\"ada\",\"contactId\":\"c12\",\"companyId\":\"\",\"dealId\":\"d12\",\"remindMinutes\":-1,\"created\":\"2026-11-22T10:00:00.000Z\"},{\"id\":\"a14\",\"type\":\"call\",\"subject\":\"Kick-off call onboarding project\",\"body\":\"\",\"due\":\"2026-08-26\",\"done\":true,\"doneAt\":\"2026-08-26T11:00:00.000Z\",\"owner\":\"me\",\"contactId\":\"c11\",\"companyId\":\"\",\"dealId\":\"d13\",\"remindMinutes\":-1,\"created\":\"2026-08-24T10:00:00.000Z\"},{\"id\":\"a15\",\"type\":\"email\",\"subject\":\"Newsletter invitation\",\"body\":\"\",\"due\":\"2026-10-25\",\"done\":true,\"doneAt\":\"2026-10-25T11:00:00.000Z\",\"owner\":\"ada\",\"contactId\":\"c6\",\"companyId\":\"\",\"dealId\":\"\",\"remindMinutes\":-1,\"created\":\"2026-10-23T10:00:00.000Z\"}],\"products\":[{\"id\":\"p1\",\"name\":\"UX workshop (day)\",\"sku\":\"WS-DAY\",\"price\":1600,\"unit\":\"day\",\"vatRate\":null,\"description\":\"Facilitated workshop with preparation and summary\"},{\"id\":\"p2\",\"name\":\"Design sprint (week)\",\"sku\":\"DS-WEEK\",\"price\":7200,\"unit\":\"week\",\"vatRate\":null,\"description\":\"\"},{\"id\":\"p3\",\"name\":\"Front-end development\",\"sku\":\"DEV-H\",\"price\":105,\"unit\":\"hour\",\"vatRate\":null,\"description\":\"\"},{\"id\":\"p4\",\"name\":\"Hosting \u0026 maintenance\",\"sku\":\"OPS-M\",\"price\":600,\"unit\":\"month\",\"vatRate\":null,\"description\":\"\"},{\"id\":\"p5\",\"name\":\"Accessibility audit (WCAG 2.2)\",\"sku\":\"A11Y\",\"price\":4800,\"unit\":\"audit\",\"vatRate\":null,\"description\":\"\"}],\"quotes\":[{\"id\":\"q1\",\"number\":\"Q-2026-0001\",\"dealId\":\"d2\",\"contactId\":\"c2\",\"companyId\":\"o2\",\"date\":\"2026-11-24\",\"validUntil\":\"2026-12-24\",\"buyerCountry\":\"DE\",\"buyerVatId\":\"\",\"lines\":[{\"productId\":\"p1\",\"description\":\"UX workshop (day)\",\"qty\":2,\"unitPrice\":1600,\"discountPct\":0,\"vatRate\":null},{\"productId\":\"p3\",\"description\":\"Front-end development\",\"qty\":120,\"unitPrice\":105,\"discountPct\":5,\"vatRate\":null},{\"productId\":\"p4\",\"description\":\"Hosting \u0026 maintenance\",\"qty\":12,\"unitPrice\":600,\"discountPct\":10,\"vatRate\":null}],\"discountPct\":0,\"notes\":\"Payment 50 % on order, 50 % on launch.\",\"status\":\"sent\"},{\"id\":\"q2\",\"number\":\"Q-2026-0002\",\"dealId\":\"d5\",\"contactId\":\"c5\",\"companyId\":\"o5\",\"date\":\"2026-11-24\",\"validUntil\":\"2026-12-24\",\"buyerCountry\":\"NL\",\"buyerVatId\":\"NL859052841B01\",\"lines\":[{\"productId\":\"p2\",\"description\":\"Design sprint (week)\",\"qty\":4,\"unitPrice\":7200,\"discountPct\":0,\"vatRate\":null},{\"productId\":\"p3\",\"description\":\"Front-end development\",\"qty\":240,\"unitPrice\":105,\"discountPct\":0,\"vatRate\":null}],\"discountPct\":3,\"notes\":\"\",\"status\":\"draft\"}],\"emailTemplates\":[{\"id\":\"intro\",\"name\":\"First contact\",\"subject\":\"Nice to meet you, {{contact.firstName}}\",\"body\":\"Hi {{contact.firstName}},\\n\\nthanks for your time today. As promised, here is a short summary of what we talked about for {{company.name}}.\\n\\nBest regards,\\n{{me.name}}\"},{\"id\":\"follow-up\",\"name\":\"Follow-up on a proposal\",\"subject\":\"Your proposal for {{deal.title}}\",\"body\":\"Hi {{contact.firstName}},\\n\\nI wanted to check whether you had a chance to look at our proposal for {{deal.title}} ({{deal.value}}). Happy to answer any questions.\\n\\nBest regards,\\n{{me.name}}\"}],\"segments\":[{\"id\":\"sg1\",\"name\":\"Decision makers with marketing consent\",\"entity\":\"contacts\",\"match\":\"all\",\"rules\":[{\"field\":\"tags\",\"op\":\"has-tag\",\"value\":\"decision-maker\"},{\"field\":\"marketing\",\"op\":\"is\",\"value\":\"yes\"}]},{\"id\":\"sg2\",\"name\":\"Closing in the next 30 days\",\"entity\":\"deals\",\"match\":\"all\",\"rules\":[{\"field\":\"status\",\"op\":\"is\",\"value\":\"open\"},{\"field\":\"expectedClose\",\"op\":\"within-days\",\"value\":\"-30\"}]},{\"id\":\"sg3\",\"name\":\"Enterprise accounts\",\"entity\":\"companies\",\"match\":\"all\",\"rules\":[{\"field\":\"tags\",\"op\":\"has-tag\",\"value\":\"enterprise\"}]}],\"customFields\":[{\"id\":\"cf1\",\"name\":\"Lead source\",\"entity\":\"deals\",\"type\":\"select\",\"options\":[\"Referral\",\"Website\",\"Event\",\"Outbound\"]},{\"id\":\"cf2\",\"name\":\"Newsletter\",\"entity\":\"contacts\",\"type\":\"checkbox\",\"options\":[]}]}",
                    "asOf": "2026-11-24",
                    "months": 12
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RapportPipelineForecastResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/rapport-csv-dedupe/calculate": {
      "post": {
        "operationId": "calculateRapportCsvDedupe",
        "summary": "Find duplicate contacts in a CSV (same e-mail, phone or similar name) and merge them.",
        "description": "Checks a contacts CSV (Rapport, HubSpot, Pipedrive or any file with name, e-mail, phone and company columns) for duplicates: the same e-mail even with different case, Gmail dots or +tags, the same phone number written differently, and very similar names at the same company. Shows every group with its reasons and gives you a merged CSV. Same rules as Rapport’s duplicate finder.\n\nMethodology:\n- Same e-mail: compared in lower case; for every provider a +tag is ignored (anna+news@ = anna@), for Gmail also dots (an.na@gmail.com = anna@gmail.com).\n- Same phone: only digits count and the last nine are compared, so +49 40 2345678 and 040 2345678 match. Numbers with fewer than seven digits are ignored.\n- Similar name: Jaro–Winkler similarity of the folded full names (accents, case and punctuation removed) of at least 0.92, AND the same company (legal forms like GmbH, Inc. or B.V. ignored) or the same non-free-mail e-mail domain. Identical names without any company or e-mail on one side are flagged as weaker matches.\n- Pairs are joined into groups. In the merged CSV the first row of each group is kept; its empty fields are filled from the others, tags are combined, notes appended and the newest documented lawful basis/consent wins.\n\nCheck each group before you delete anything in your CRM: two real people can share a phone number or a name.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "rapport_csv_dedupe",
        "x-owner-app": "rapport",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RapportCsvDedupeInput"
              },
              "examples": {
                "example1": {
                  "summary": "HubSpot contacts export with three duplicate pairs",
                  "value": {
                    "csv": "Record ID,First Name,Last Name,Email,Phone Number,Job Title,Company Name,Contact owner,Create Date,Last Activity Date,Marketing contact status,Legal basis for processing contact's data\r\n101,Lena,Vogt,lena.vogt@mediq.example,+49 89 7654321,Marketing Director,Mediq Health GmbH,Mara Lindqvist,2026-08-12 09:14,2026-11-20 15:02,Marketing contact,Freely given consent from contact\r\n102,Lena,Vogt,Lena.Vogt@mediq.example,,Marketing,Mediq Health,Jonas Becker,2026-11-03 11:40,,Non-marketing contact,\r\n103,Paul,Hansen,paul@hansen-kaffee.example,040 2345678,Owner,Kaffeerösterei Hansen,Jonas Becker,2025-12-01 10:00,2026-11-10 09:30,Non-marketing contact,Performance of a contract\r\n104,Paul,Hansen,,+49 40 2345678,Inhaber,Kaffeeroesterei Hansen,Jonas Becker,2026-02-14 16:20,,Non-marketing contact,\r\n105,Daan,de Vries,daan.devries@greenway.example,+31 10 555 0101,CIO,Greenway Logistics B.V.,Mara Lindqvist,2026-09-15 13:00,2026-11-18 10:15,Non-marketing contact,Legitimate interest – prospect/lead\r\n106,Sanne,Bakker,sanne.bakker@greenway.example,+31 10 555 0144,E-commerce Manager,Greenway Logistics B.V.,Ada Okafor,2026-09-20 08:45,2026-11-18 10:15,Marketing contact,Freely given consent from contact\r\n107,Sanne,Baker,s.bakker+events@greenway.example,,E-commerce,Greenway Logistics,Ada Okafor,2026-10-30 18:02,,Non-marketing contact,\r\n108,Ingrid,Halvorsen,ingrid.halvorsen@fjordline.example,+47 55 12 34 56,Head of Digital,Fjordline Ferries AS,Mara Lindqvist,2026-04-19 09:00,2026-11-21 14:00,Non-marketing contact,Legitimate interest – existing customer\r\n109,Yusuf,Demir,yusuf.demir@gmail.example,,Founder,,Ada Okafor,2026-11-07 20:11,,Marketing contact,Freely given consent from contact\r\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RapportCsvDedupeResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "summary": "Multi-tool workflows",
        "responses": {
          "200": {
            "description": "Workflow list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "RapportVcardConvertInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "text": {
            "title": "vCards or contacts CSV",
            "description": "Paste vCards (BEGIN:VCARD … END:VCARD) to get a CSV, or a CSV with a header row to get vCards.",
            "type": "string",
            "maxLength": 5000000,
            "default": ""
          },
          "file": {
            "title": "File (optional)",
            "description": "Used instead of the pasted text when given. Upload as {filename, contentType?, contentBase64}. Max 9766 KiB. Accepts .vcf,.vcard,.csv,text/vcard,text/csv.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "version": {
            "title": "vCard version to write",
            "type": "string",
            "enum": [
              "4.0",
              "3.0"
            ],
            "default": "4.0"
          }
        },
        "required": []
      },
      "RapportVcardConvertResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "direction",
              "count"
            ],
            "properties": {
              "direction": {
                "type": "string"
              },
              "count": {
                "type": "integer"
              },
              "versions": {
                "type": "array"
              },
              "contacts": {
                "type": "array"
              },
              "warnings": {
                "type": "array"
              },
              "csvArtifact": {
                "type": "string"
              },
              "vcfArtifact": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "RapportPipelineForecastInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "deals": {
            "title": "Deals (CSV or Rapport file)",
            "description": "Needs a title and a value column; stage, status (open/won/lost), probability, expected close, created, closed and owner columns are used when present.",
            "type": "string",
            "maxLength": 5000000,
            "default": ""
          },
          "dealsFile": {
            "title": "File (optional)",
            "description": "Used instead of the pasted text when given. Upload as {filename, contentType?, contentBase64}. Max 9766 KiB. Accepts .csv,.json,text/csv,application/json.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "asOf": {
            "title": "Today is",
            "description": "Deals expected before this day count as overdue; the months start here. Empty = today.",
            "type": "string",
            "format": "date"
          },
          "months": {
            "title": "Months to forecast",
            "type": "number",
            "minimum": 1,
            "maximum": 24,
            "default": 6
          },
          "from": {
            "title": "Closed from (optional)",
            "description": "Win rate and sales cycle count deals closed in this window. Empty = 12 months up to “Today is”.",
            "type": "string",
            "format": "date"
          },
          "to": {
            "title": "Closed until (optional)",
            "type": "string",
            "format": "date"
          },
          "pipeline": {
            "title": "Pipeline (optional)",
            "description": "Name of one pipeline; empty = all.",
            "type": "string",
            "maxLength": 60,
            "default": ""
          }
        },
        "required": []
      },
      "RapportPipelineForecastResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "open",
              "stages",
              "months",
              "winRate",
              "cycle"
            ],
            "properties": {
              "asOf": {
                "type": "string"
              },
              "from": {
                "type": "string"
              },
              "to": {
                "type": "string"
              },
              "currency": {
                "type": "string"
              },
              "pipelineId": {
                "type": "string"
              },
              "pipelineName": {
                "type": "string"
              },
              "source": {
                "type": "string"
              },
              "deals": {
                "type": "integer"
              },
              "open": {
                "type": "object"
              },
              "stages": {
                "type": "array"
              },
              "months": {
                "type": "array"
              },
              "overdue": {
                "type": "object"
              },
              "won": {
                "type": "object"
              },
              "lost": {
                "type": "object"
              },
              "winRate": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "winRateByValue": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "cycle": {
                "type": "object"
              },
              "owners": {
                "type": "array"
              },
              "activities": {
                "type": "array"
              },
              "warnings": {
                "type": "array"
              },
              "svgArtifact": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "RapportCsvDedupeInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "csv": {
            "title": "Contacts CSV",
            "description": "With a header row. Names, e-mail, phone and company are used; other columns are kept in the merged file when Rapport knows them.",
            "type": "string",
            "maxLength": 5000000,
            "default": ""
          },
          "csvFile": {
            "title": "CSV file (optional)",
            "description": "Used instead of the pasted text when given. Upload as {filename, contentType?, contentBase64}. Max 9766 KiB. Accepts .csv,text/csv.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          }
        },
        "required": []
      },
      "RapportCsvDedupeResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "rows",
              "groups",
              "duplicates"
            ],
            "properties": {
              "rows": {
                "type": "integer"
              },
              "duplicates": {
                "type": "integer"
              },
              "groups": {
                "type": "array"
              },
              "mapping": {
                "type": "object"
              },
              "warnings": {
                "type": "array"
              },
              "mergedArtifact": {
                "type": "string"
              },
              "reportArtifact": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}