API and MCP

Works with your AI assistant, and your code

Connect Claude or another MCP client, and it can read your CRM's modules and fields, propose a mapping, test it and save it as a template. Then a person opens the template in Sloose, checks it and runs the import. For your own scripts, everything an API token can do is in the API reference.

Start freeRead the MCP guide

Connect Claude to your CRM through Sloose

Point your MCP client at Sloose's MCP server:

https://api.sloose.com/mcp

The client signs you in with OAuth 2.1. You sign in to Sloose, choose which organisation the assistant may use, and press Allow. There is no key to copy.

  • The assistant works as you, in that one organisation, at your role. Its tools never act above your role.
  • When your access to the organisation ends, so does the assistant's.
  • You can see and revoke every assistant you allowed under Your account, Apps with access.
The Sloose consent page asking whether to let an AI assistant use an organisation.
An assistant connects by OAuth. You choose the organisation it may use.

From a spreadsheet to a template, in one conversation

Describe the file to your assistant, or give it the columns. This is the order of work the tools are built for.

  1. Connect and allow

    OAuth sign-in, and you choose the organisation on the consent page.

  2. Read your CRM: list_modules, get_fields

    The assistant works from your real modules and fields, not a guess.

  3. Propose: propose_matching, propose_mapping

    How existing records are recognised, then which column feeds which field. These two use AI credits.

  4. Test: test_expression

    Any formula is run on sample rows before anyone relies on it.

  5. Check: validate_template

    The template is checked without saving it, as Validate would check it.

  6. Save: save_template

    Saved under the same rules about roles and sharing as a person.

  7. Open the template in Sloose, start an import from it, run a dry run, then import.

A real session with claude-sonnet-5-5, recorded 3 October 2026.

  1. You

    I have a spreadsheet of leads from an expo and want it in Zoho CRM as an account, a contact and a deal for each row. Please work out how it should be imported using the Sloose tools, check it, and save it as a template called "Expo leads". The Sloose connection to use is 01a100aa-c5ae-7797-81ad-7cb6addb0f6d. Here is the file: Company,Contact,Job title,Email,Mobile,Opportunity,Value,Stage,Expected close Brightwater Joinery Pty Ltd,Priya Ramanathan,Operations Manager,priya.r@brightwater.example,0491 570 156,Workshop fit-out,"$48,500",Quote sent,15/11/2026 Brightwater Joinery Pty Ltd,Tom Okafor,Purchasing,tom@brightwater.example,0491 570 157,Spare parts contract,"$6,200",Qualified,30/11/2026 Kestrel Ridge Hire,Lena Fischer,Owner,lena@kestrelridge.example,0491 570 158,Fleet tracking pilot,"$12,000",Discovery,1/12/2026 Saltbush Solar Co.,Marcus Bell,Project Lead,m.bell@saltbush.example,0491 570 159,Warehouse roof array,"$96,750",Negotiation,20/12/2026 saltbush solar co,Aisha Rahman,Finance,aisha.rahman@saltbush.example,0491 570 110,Warehouse roof array,"$96,750",Negotiation,20/12/2026 Tidewell Plumbing,Sam Nguyen,Director,sam@tidewell.example,0491 571 266,Service agreement,"9,600",quote sent,2026-12-05 Orchard Lane Catering,Grace Liu,Events Coordinator,grace@orchardlane.example,,Christmas functions,"$3,400",Won,28/10/2026
  2. Tool call

    list_modules

    What it answered
    {
      "creationOrder": [
        "accounts",
        "contacts",
        "deals"
      ],
      "dateFormat": "DMY",
      "defaultEnabled": [],
      "expressionContext": "rec",
      "modules": [
        {
          "apiName": "Accounts",
          "defaultMatch": {
            "expression": "",
            "searchField": "",
            "searchMethod": "equals"
          },
          "key": "accounts",
          "label": "Accounts",
          "singular": "Account",
          "uniqueFields": [
            "Account_Number"
          ]
        },
        {
          "apiName": "Contacts",
          "defaultMatch": {
            "expression": "",
            "searchField": "",
            "searchMethod": "equals"
          },
          "key": "contacts",
          "label": "Contacts",
          "singular": "Contact",
          "uniqueFields": []
        },
        {
          "apiName": "Deals",
          "defaultMatch": {
            "expression": "",
            "searchField": "",
            "searchMethod": "equals"
          },
          "key": "deals",
          "label": "Deals",
          "singular": "Deal",
          "uniqueFields": []
        }
      ],
      "timezone": "Australia/Sydney"
    }
  3. Tool call

    get_fieldsmodule: accounts

    What it answered
    {
      "fields": [
        {
          "aliases": [],
          "apiName": "Account_Name",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Account Name",
          "lookupTarget": null,
          "maxLength": 200,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": true,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Account_Number",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Account Number",
          "lookupTarget": null,
          "maxLength": 40,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Account_Type",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "picklist",
          "label": "Account Type",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 11,
          "options": [
            "Analyst",
            "Competitor",
            "Customer",
            "Distributor",
            "Integrator",
            "Investor",
            "Other",
            "Partner",
            "Press",
            "Prospect",
            "Reseller"
          ],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Annual_Revenue",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "currency",
          "label": "Annual Revenue",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Billing_City",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Billing City",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Billing_Code",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Billing Code",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Billing_Country",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Billing Country",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Billing_State",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "picklist",
          "label": "Billing State",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 602,
          "options": [
            "-None-",
            "Australian Capital Territory",
            "California",
            "New South Wales",
            "New York",
            "Northern Territory",
            "Queensland",
            "South Australia",
            "Tasmania",
            "Texas",
            "Victoria (Australia)",
            "Victoria (Malta)",
            "Washington",
            "Western Australia",
            " Daegu",
            " Jeollanam-do",
            "Abyan",
            "Agusan del Norte",
            "Agusan del Sur",
            "Ahal Region",
            "Al Bayda'",
            "Al Daayen",
            "Al Janūbịyah",
            "Al Madinah",
            "Al Muḩarraq",
            "Al Wakrah",
            "Al Wusţá",
            "Al ‘Āşimah",
            "Al-Hasakah",
            "Al-Qassim",
            "Alagoas",
            "Alajuela",
            "Alaska",
            "Alberta",
            "Alto Paraguay",
            "Amnat Charoen",
            "Andaman and Nicobar Islands",
            "Anibare District",
            "Anjouan",
            "Antalya",
            "Appenzell Innerrhoden",
            "Ardahan",
            "Arkansas",
            "Armavir Region",
            "Artemisa Province",
            "As-Suwayda",
            "Atakora",
            "Atlantique",
            "Atlántico",
            "Atua",
            "Atyrau Region",
            "Au Cap",
            "Ayacucho",
            "Azua",
            "Badajoz",
            "Baghlan",
            "Bagmati Zone",
            "Baja California Sur",
            "Balakan District",
            "Balzan"
          ],
          "optionsTruncated": true,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Billing_Street",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Billing Street",
          "lookupTarget": null,
          "maxLength": 250,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Description",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "textarea",
          "label": "Description",
          "lookupTarget": null,
          "maxLength": 32000,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Employees",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "integer",
          "label": "Employees",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Industry",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "picklist",
          "label": "Industry",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 9,
          "options": [
            "Retail",
            "Technology",
            "Manufacturing",
            "Logistics",
            "Communications",
            "Consulting",
            "Education",
            "Financial Services",
            "Government"
          ],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Phone",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "phone",
          "label": "Phone",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Tax_Number",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Tax Number",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Website",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "website",
          "label": "Website",
          "lookupTarget": null,
          "maxLength": 255,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        }
      ],
      "module": "accounts"
    }
  4. Tool call

    get_fieldsmodule: contacts

    What it answered
    {
      "fields": [
        {
          "aliases": [],
          "apiName": "Account_Name",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "lookup",
          "label": "Account Name",
          "lookupTarget": "Accounts",
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Description",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "textarea",
          "label": "Description",
          "lookupTarget": null,
          "maxLength": 32000,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Email",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "email",
          "label": "Email",
          "lookupTarget": null,
          "maxLength": 100,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Fee_Paid",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "currency",
          "label": "Fee Paid",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "First_Name",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "First Name",
          "lookupTarget": null,
          "maxLength": 40,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Last_Name",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Last Name",
          "lookupTarget": null,
          "maxLength": 80,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": true,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Lead_Source",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "picklist",
          "label": "Lead Source",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 11,
          "options": [
            "Advertisement",
            "Chat",
            "Cold Call",
            "Employee Referral",
            "External Referral",
            "Online Store",
            "Partner",
            "Public Relations",
            "Trade Show",
            "Web Download",
            "Web Research"
          ],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Mailing_City",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Mailing City",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Mailing_Country",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Mailing Country",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Mobile",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "phone",
          "label": "Mobile",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Phone",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "phone",
          "label": "Phone",
          "lookupTarget": null,
          "maxLength": 30,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Registered_On",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "date",
          "label": "Registered On",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Session_Date",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "date",
          "label": "Session Date",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Title",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Title",
          "lookupTarget": null,
          "maxLength": 100,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        }
      ],
      "module": "contacts"
    }
  5. Tool call

    get_fieldsmodule: deals

    What it answered
    {
      "fields": [
        {
          "aliases": [],
          "apiName": "Account_Name",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "lookup",
          "label": "Account Name",
          "lookupTarget": "Accounts",
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Amount",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "currency",
          "label": "Amount",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Campaign_Source",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Campaign Source",
          "lookupTarget": null,
          "maxLength": 100,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Closing_Date",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "date",
          "label": "Closing Date",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Contact_Name",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "lookup",
          "label": "Contact Name",
          "lookupTarget": "Contacts",
          "maxLength": null,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": false,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Deal_Name",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "text",
          "label": "Deal Name",
          "lookupTarget": null,
          "maxLength": 120,
          "mustBe": null,
          "optionCount": 0,
          "options": [],
          "optionsTruncated": false,
          "required": true,
          "writtenAs": null
        },
        {
          "aliases": [],
          "apiName": "Stage",
          "derived": false,
          "description": null,
          "excludeFromAi": false,
          "format": null,
          "kind": "picklist",
          "label": "Stage",
          "lookupTarget": null,
          "maxLength": null,
          "mustBe": null,
          "optionCount": 7,
          "options": [
            "Qualification",
            "Needs Analysis",
            "Value Proposition",
            "Proposal",
            "Negotiation",
            "Closed Won",
            "Closed Lost"
          ],
          "optionsTruncated": false,
          "required": true,
          "writtenAs": null
        }
      ],
      "module": "deals"
    }
  6. Tool call

    propose_matchingcolumns: ["Company","Contact","Job title","E…, modules: ["accounts","contacts","deals"], sampleRows: [{"Compa…

    What it answered
    {
      "credits": 5,
      "declinedAgain": [],
      "modules": [
        "accounts",
        "contacts",
        "deals"
      ],
      "notes": [],
      "requestId": "01a100aa-f441-76cc-9e1a-757bbaa6923d",
      "rules": [
        {
          "confidence": 0.6,
          "expression": "helpers.trim(row.Company)",
          "field": "Account_Name",
          "method": "equals",
          "module": "accounts",
          "outputs": {
            "rows": 3,
            "samples": [
              "Brightwater Joinery Pty Ltd",
              "saltbush solar co",
              "Tidewell Plumbing"
            ]
          },
          "reason": "The file has no account number, so the company name is the best way to recognise an existing account."
        },
        {
          "confidence": 0.75,
          "expression": "helpers.lower(helpers.trim(row.Email))",
          "field": "Email",
          "method": "equals",
          "module": "contacts",
          "outputs": {
            "rows": 3,
            "samples": [
              "priya.r@brightwater.example",
              "aisha.rahman@saltbush.exampl…",
              "sam@tidewell.example"
            ]
          },
          "reason": "Each contact has a distinct email address, which is the most reliable way to recognise an existing contact."
        },
        {
          "confidence": 0.55,
          "expression": "helpers.trim(row.Opportunity)",
          "field": "Deal_Name",
          "method": "equals",
          "module": "deals",
          "outputs": {
            "rows": 3,
            "samples": [
              "Workshop fit-out",
              "Warehouse roof array",
              "Service agreement"
            ]
          },
          "reason": "The opportunity name is the only distinct text that can identify an existing deal."
        }
      ],
      "usage": {
        "cacheCreationInputTokens": 7814,
        "cacheReadInputTokens": 0,
        "inputTokens": 1439,
        "outputTokens": 274
      }
    }
  7. Tool call

    propose_mappingcolumns: ["Company","Contact","Job title","E…, enabledModules: ["accounts","contacts","deals"], sampleRows: […

    What it answered
    {
      "columns": [
        {
          "apiName": "Account_Name",
          "column": "Company",
          "confidence": 0.95,
          "mode": "column",
          "module": "accounts",
          "reason": "Company names fill the account name directly.",
          "searchField": null,
          "status": "accepted",
          "transform": null
        },
        {
          "apiName": "Account_Name",
          "column": "Company",
          "confidence": 0.9,
          "mode": "expression",
          "module": "contacts",
          "outputs": {
            "rows": 0,
            "runtime": true,
            "samples": []
          },
          "reason": "Accounts are imported first, so each contact links to the account created from the same row.",
          "searchField": null,
          "status": "accepted",
          "transform": "rec.Account.id"
        },
        {
          "apiName": "Account_Name",
          "column": "Company",
          "confidence": 0.9,
          "mode": "expression",
          "module": "deals",
          "outputs": {
            "rows": 0,
            "runtime": true,
            "samples": []
          },
          "reason": "Each deal links to the account created from the same row.",
          "searchField": null,
          "status": "accepted",
          "transform": "rec.Account.id"
        },
        {
          "apiName": "First_Name",
          "column": "Contact",
          "confidence": 0.8,
          "mode": "expression",
          "module": "contacts",
          "outputs": {
            "rows": 3,
            "runtime": false,
            "samples": [
              "Priya",
              "Aisha",
              "Sam"
            ]
          },
          "reason": "The first word of the full name becomes the first name.",
          "searchField": null,
          "status": "accepted",
          "transform": "helpers.split(row.Contact, ' ', 0)"
        },
        {
          "apiName": "Last_Name",
          "column": "Contact",
          "confidence": 0.75,
          "mode": "expression",
          "module": "contacts",
          "outputs": {
            "rows": 3,
            "runtime": false,
            "samples": [
              "Ramanathan",
              "Rahman",
              "Nguyen"
            ]
          },
          "reason": "The last word of the full name becomes the last name, which is required.",
          "searchField": null,
          "status": "accepted",
          "transform": "helpers.split(row.Contact, ' ', 1)"
        },
        {
          "apiName": "Contact_Name",
          "column": "Contact",
          "confidence": 0.9,
          "mode": "expression",
          "module": "deals",
          "outputs": {
            "rows": 0,
            "runtime": true,
            "samples": []
          },
          "reason": "Each deal links to the contact created from the same row.",
          "searchField": null,
          "status": "accepted",
          "transform": "rec.Contact.id"
        },
        {
          "apiName": "Title",
          "column": "Job title",
          "confidence": 0.95,
          "mode": "column",
          "module": "contacts",
          "reason": "Job titles fit the contact title field.",
          "searchField": null,
          "status": "accepted",
          "transform": null
        },
        {
          "apiName": "Email",
          "column": "Email",
          "confidence": 0.97,
          "mode": "column",
          "module": "contacts",
          "reason": "These are email addresses and fit the email field.",
          "searchField": null,
          "status": "accepted",
          "transform": null
        },
        {
          "apiName": "Mobile",
          "column": "Mobile",
          "confidence": 0.95,
          "mode": "column",
          "module": "contacts",
          "reason": "Mobile numbers go straight into the mobile field.",
          "searchField": null,
          "status": "accepted",
          "transform": null
        },
        {
          "apiName": "Deal_Name",
          "column": "Opportunity",
          "confidence": 0.9,
          "mode": "column",
          "module": "deals",
          "reason": "Opportunity names are the deal names.",
          "searchField": null,
          "status": "accepted",
          "transform": null
        },
        {
          "apiName": "Amount",
          "column": "Value",
          "confidence": 0.9,
          "mode": "expression",
          "module": "deals",
          "outputs": {
            "rows": 3,
            "runtime": false,
            "samples": [
              "48500",
              "96750",
              "9600"
            ]
          },
          "reason": "Strips the dollar sign and commas to give a number.",
          "searchField": null,
          "status": "accepted",
          "transform": "helpers.num(row.Value)"
        },
        {
          "apiName": "Stage",
          "column": "Stage",
          "confidence": 0.85,
          "mode": "column",
          "module": "deals",
          "reason": "Stage values are matched to the listed options at Translate values.",
          "searchField": null,
          "status": "accepted",
          "transform": null
        },
        {
          "apiName": "Closing_Date",
          "column": "Expected close",
          "confidence": 0.85,
          "mode": "expression",
          "module": "deals",
          "outputs": {
            "rows": 3,
            "runtime": false,
            "samples": [
              "2026-11-15",
              "2026-12-20",
              "2026-12-05"
            ]
          },
          "reason": "Dates are mostly day/month/year, and ISO dates like 2026-12-05 are also read.",
          "searchField": null,
          "status": "accepted",
          "transform": "helpers.date(row[\"Expected close\"], \"DD/MM/YYYY\")"
        }
      ],
      "credits": 6,
      "enabledModules": [
        "accounts",
        "contacts",
        "deals"
      ],
      "mappings": {
        "accounts": {
          "Account_Name": {
            "mode": "column",
            "skip": false,
            "source": "Company",
            "staticValue": null,
            "transform": null
          }
        },
        "contacts": {
          "Account_Name": {
            "mode": "expression",
            "skip": false,
            "source": null,
            "staticValue": null,
            "transform": "rec.Account.id"
          },
          "Email": {
            "mode": "column",
            "skip": false,
            "source": "Email",
            "staticValue": null,
            "transform": null
          },
          "First_Name": {
            "mode": "expression",
            "skip": false,
            "source": null,
            "staticValue": null,
            "transform": "helpers.split(row.Contact, ' ', 0)"
          },
          "Last_Name": {
            "mode": "expression",
            "skip": false,
            "source": null,
            "staticValue": null,
            "transform": "helpers.split(row.Contact, ' ', 1)"
          },
          "Mobile": {
            "mode": "column",
            "skip": false,
            "source": "Mobile",
            "staticValue": null,
            "transform": null
          },
          "Title": {
            "mode": "column",
            "skip": false,
            "source": "Job title",
            "staticValue": null,
            "transform": null
          }
        },
        "deals": {
          "Account_Name": {
            "mode": "expression",
            "skip": false,
            "source": null,
            "staticValue": null,
            "transform": "rec.Account.id"
          },
          "Amount": {
            "mode": "expression",
            "skip": false,
            "source": null,
            "staticValue": null,
            "transform": "helpers.num(row.Value)"
          },
          "Closing_Date": {
            "mode": "expression",
            "skip": false,
            "source": null,
            "staticValue": null,
            "transform": "helpers.date(row[\"Expected close\"], \"DD/MM/YYYY\")"
          },
          "Contact_Name": {
            "mode": "expression",
            "skip": false,
            "source": null,
            "staticValue": null,
            "transform": "rec.Contact.id"
          },
          "Deal_Name": {
            "mode": "column",
            "skip": false,
            "source": "Opportunity",
            "staticValue": null,
            "transform": null
          },
          "Stage": {
            "mode": "column",
            "skip": false,
            "source": "Stage",
            "staticValue": null,
            "transform": null
          }
        }
      },
      "notes": [],
      "requestId": "01a100ab-012d-7713-a341-0745256456e1",
      "usage": {
        "cacheCreationInputTokens": 7843,
        "cacheReadInputTokens": 0,
        "inputTokens": 620,
        "outputTokens": 1092
      }
    }
  8. Tool call

    test_expressioncolumns: ["Expected close"], expression: helpers.date(row["Expected close"],…, sampleRows: [{"Expected close"…

    What it answered
    {
      "compileError": null,
      "compiled": true,
      "firstError": null,
      "ok": true,
      "referencesRecords": false,
      "results": [
        {
          "error": null,
          "row": 1,
          "value": "2026-11-15"
        },
        {
          "error": null,
          "row": 2,
          "value": "2026-12-01"
        },
        {
          "error": null,
          "row": 3,
          "value": "2026-12-05"
        },
        {
          "error": null,
          "row": 4,
          "value": "2026-10-28"
        }
      ]
    }
  9. Tool call

    test_expressioncolumns: ["Company"], expression: helpers.trim(row.Company).replace(/…, sampleRows: [{"Company":"Saltbush Sol…

    What it answered
    {
      "compileError": null,
      "compiled": true,
      "firstError": null,
      "ok": true,
      "referencesRecords": false,
      "results": [
        {
          "error": null,
          "row": 1,
          "value": "Saltbush Solar Co"
        },
        {
          "error": null,
          "row": 2,
          "value": "saltbush solar co"
        },
        {
          "error": null,
          "row": 3,
          "value": "Tidewell Plumbing"
        }
      ]
    }
  10. Tool call

    validate_templateenabledModules: ["accounts","contacts","deals"], columns: ["Company","Contact","Job title","E…, fieldMappings…

    What it answered
    {
      "issueCount": 0,
      "issues": {
        "accounts": {
          "expressions": [],
          "picklistValues": [],
          "types": []
        },
        "contacts": {
          "expressions": [],
          "picklistValues": [],
          "types": []
        },
        "deals": {
          "expressions": [],
          "picklistValues": [],
          "types": []
        }
      },
      "libraryProblems": [],
      "ok": true,
      "problems": []
    }
  11. Tool call

    save_templatename: Expo leads, description: Expo lead sheet: one account, conta…, config: {"enabledModules":["accounts","c…

    What it answered
    {
      "created": true,
      "id": "01a100ab-83f4-7070-bee1-abef43545f90",
      "updatedAt": "2026-10-03T07:30:02.868Z",
      "version": 1
    }
  12. Assistant

    I've saved the "Expo leads" template (id 01a100ab-83f4-7070-bee1-abef43545f90). It passed validation with no issues. I haven't run an import with it, so it hasn't been tried on your actual file.

    What it does for each row

    • Account: the name comes from Company, with spaces and any trailing full stop removed. Existing accounts are matched on that name.
    • Contact: the first and last name are split from Contact. Title, Email and Mobile come across as they are. The contact links to the row's account and is matched on lowercase email.
    • Deal: Deal Name comes from Opportunity and Amount from Value, with $ and commas removed. Closing Date is read as day/month/year, and it handled 15/11/2026, 1/12/2026 and the ISO 2026-12-05. The deal links to the row's account and contact and is matched on deal name.

    Stage translation. Your stages aren't Zoho's, so I mapped them as follows. Please check these:

    • Quote sent (any capitalisation) becomes Proposal.
    • Qualified becomes Qualification.
    • Discovery becomes Needs Analysis.
    • Negotiation stays Negotiation.
    • Won becomes Closed Won.

    Things to check

    • Saltbush: "Saltbush Solar Co." and "saltbush solar co" should become one account, but only if Zoho's name match ignores capitalisation. I couldn't confirm that. If it doesn't, you'll get a duplicate Saltbush account, which is easy to merge afterwards.
    • Warehouse roof array: it appears twice, once for Marcus and once for Aisha. Matching on deal name means it should be created once, linked to Marcus (the first row). Aisha will still be created as a contact on the same account.
    • Deal matching: deals are matched on name alone, so two different companies with an identically named deal would be treated as the same deal.
    • Contact names: the split assumes two-word names, which is true for every row here. A name like "Mary Ann Smith" would break.
    • Empty mobile: Grace Liu's mobile is blank, so that field is left empty.
    • Lead Source: I didn't set it. If you want these contacts tagged as "Trade Show", that's a one-line addition.
An assistant proposes and saves a template. Nothing is imported until a person runs it.

No tool runs an import

An assistant can read, propose, test and save a template. No tool writes a record to your CRM or starts a run. Deciding what counts as the same record is a judgement about your data, so a person always looks before anything is written.

The MCP tools

Nine tools. Two of them ask the AI and use AI credits; the other seven cost nothing.

ToolWhat it doesAI credits
list_modulesThe modules your CRM connection offers.No
get_fieldsA module’s fields, with the notes your administrators added.No
propose_matchingHow an existing record is recognised, per module.Yes
propose_mappingA mapping for a set of columns, checked against your real fields.Yes
test_expressionRuns a formula on sample rows, in an isolated sandbox.No
validate_templateChecks a template without saving it.No
list_templatesThe templates you can see.No
get_templateOne template.No
save_templateCreates or updates a template, under the same rules as a person.No

MCP is on the Business and Enterprise plans, and during a trial. Details, and what to send each tool, are inConnect an agent (MCP).

A CRM import API for your own scripts

Everything Sloose's own pages do goes through one API. The API reference is generated from its route definitions and covers everything an API token can do. With it you can read a connection's modules and fields, keep your field settings, create and update templates, create imports and upload their files, read run history and download a run's results file.

Sloose does not run imports on its servers. A run happens in Sloose, in a browser, and writes through your organisation's connection.

Organisation API tokens

  • An administrator creates them in settings. The secret is shown once, and Sloose keeps only a hash of it.
  • Each one works in one organisation, with an expiry of 30 days, 90 days, a year, or none.
  • It acts as the person who made it, never above their role today.
  • A token can read, configure and import. It cannot create tokens, invite people, change roles, connect or disconnect a CRM, or change billing.
  • Revoking one stops it on its next request.

API tokens, in the docs

Questions people ask

How do I connect Claude to my CRM?

Add Sloose's MCP server, https://api.sloose.com/mcp, to Claude. Claude opens Sloose's sign-in, you choose the organisation and press Allow. Claude can then read your CRM's modules and fields through Sloose and save templates. It cannot write records.

Which AI assistants can connect?

MCP clients that sign in with OAuth and register by a Client ID Metadata Document, which is how Claude connects. A client that lets you set a request header can send an organisation API token instead. Either way, the organisation needs a plan that includes MCP.

Can an AI assistant import data into my CRM through Sloose?

It can prepare the import, not run it. The tools read your CRM's shape, propose and test a mapping, and save a template. A person opens it in Sloose, checks it with Validate and a dry run, and runs it.

Do the MCP tools use AI credits?

Only propose_matching and propose_mapping, which ask the AI. A request that fails is not charged. The other seven tools cost nothing.

Is it safe to give an AI assistant access to my CRM?

Through Sloose, an assistant works in one organisation, at your role, and loses access when you do. It cannot write a record or start a run, and you can revoke it at any time under Your account.

Let your assistant draft the template. You run the import.

MCP is included on Business and Enterprise, and during a trial.

Start freeRead the MCP guide