First-party app
kvCORE

kvCORE

Manage contacts, notes, tags, users, offices and teams in kvCORE / BoldTrail, Inside Real Estate's real-estate CRM.

stable Customer Relationship ManagementMarketing

About

kvCORE ships in the w6w first-party pack. It declares 26 actions, 2 health checks, and the host runs its code in a sandbox that never sees the credential.

App id
io.w6w.kvcore
Version
0.1.0
Author
w6w
Licence
MIT
Categories
Customer Relationship Management · Marketing

Overview

kvCORE (by Inside Real Estate, now rebranded BoldTrail) is a real-estate CRM and lead-engine platform: brokerages and agent teams run their contact database, lead routing, agent websites and office/team structure through it. This app covers the kvCORE Public API V2 — the API that is actually live today at api.kvcore.com — for contact and lead management (create, read, list, update, tag, and note contacts) and account administration (create, read, list, update and delete users, offices and teams, including team/office membership).

Inside Real Estate is mid-rebrand: its developer hub now documents a second, OAuth-based BoldTrail API (api.boldtrail.com) that its own docs describe as beta and invite-only as of this writing, with no self-serve way to obtain a client. This app deliberately targets the V2 API instead, because it is the one a workflow can actually authenticate against today: any kvCORE user can self-issue a scoped bearer token from their own Lead Dropbox, no partner approval required.

Every endpoint, field and error shape here was verified against the vendor’s own OpenAPI 3.1 document (embedded in developer.insiderealestate.com’s reference pages, fetched 2026-09-29) plus a live, unauthenticated probe against api.kvcore.com on the same day.

Build with kvCORE

Three routes to the same 26 actions. The Workflow tab is generated from kvCORE's own manifest and carries its real ids, so it is copy-pasteable; the Code and CLI examples are the same call for any action on any app, so every app-specific value in them is a blank you fill in.

Create Contact

contact-create

Create a new kvCORE contact/lead. Search first — kvCORE permits duplicate contacts and does not de-duplicate for you.

Get Contact

contact-get

Fetch a single contact by ID.

List Contacts

contact-list

Search contacts. Combine filters to narrow the result — see the field hints below.

Add Note to Contact

contact-note-add

Add a note to a contact. A contact created moments earlier via Create Contact may not be ready to receive a note for up to 30 seconds.

Add Tags to Contact

contact-tags-add

Add one or more hashtags to a contact. Existing tags are left untouched.

Remove Tags from Contact

contact-tags-remove

Disassociate one or more hashtags from a contact. The tag itself is not deleted from the account. Locked tags can only be removed by an admin-scoped token.

Update Contact

contact-update

Update fields on an existing contact. Only the fields you set are changed.

Create Office

office-create

Create a new office on the account.

Remove Office

office-delete

Remove an office from the account.

Get Office

office-get

Fetch a single office by ID.

List Offices

office-list

List offices on the account.

Update Office

office-update

Update fields on an existing office. Only the fields you set are changed.

Add User to Office

office-user-add

Add an existing user to an office, optionally as an office admin.

Remove User from Office

office-user-remove

Remove a user from an office. Does not delete the user account itself.

Create Team

team-create

Create a new team on the account.

Remove Team

team-delete

Remove a team from the account.

Get Team

team-get

Fetch a single team by ID.

List Teams

team-list

List teams on the account.

Update Team

team-update

Update fields on an existing team. The vendor requires `name` even on update.

Add User to Team

team-user-add

Add an existing user to a team, optionally as a team admin.

Remove User from Team

team-user-remove

Remove a user from a team. Does not delete the user account itself.

Create User

user-create

Create a new user (agent or lender). Requires an All-scoped token.

Remove User

user-delete

Remove a user from the account. Their leads round-robin to all agents unless you name a reassignment target below.

Get User

user-get

Fetch a single user's profile by ID.

List Users

user-list

List users on the account. Combine filters to narrow the result.

Update User

user-update

Update fields on an existing user. Only the fields you set are changed.

A workflow step names the app and the action, and the editor fills in the connection when you pick one. This is the Step shape from the workflow spec, carrying kvCORE's real ids.

{
  "manifestVersion": "2",
  "name": "kvcore-example",
  "steps": [
    {
      "id": "contact-create",
      "uses": {
        "app": "io.w6w.kvcore",
        "action": "contact-create",
        "connection": "conn_YOUR_CONNECTION_ID"
      },
      "with": {
        "first_name": "<first_name>",
        "last_name": "<last_name>",
        "email": "<email>"
      }
    }
  ]
}

Here are some of the things you can do

  • Create Contact

    perform
    contact-create
  • Get Contact

    read
    contact-get
  • List Contacts

    search
    contact-list
  • Add Note to Contact

    perform
    contact-note-add
  • Add Tags to Contact

    perform
    contact-tags-add

+21 more actions available

Every app-specific value here is a blank you have to fill in. An app action is reached through the connection that authenticates it, so the address is a connection id, not the app id — and connections belong to your account, so a public page cannot know yours. Create one for kvCORE, then fill in the three blanks: conn_YOUR_CONNECTION_ID, the action key, and the parameters that action declares. The call itself is real — the shape is transcribed from the studio's own snippet builder, which prints the same kind of blanks — but nothing in it is specific to kvCORE. The Workflow tab is where this app's real ids are.

Install
npm install @w6w/sdk
yarn add @w6w/sdk
pnpm add @w6w/sdk
deno add npm:@w6w/sdk
Code
import { W6wClient, isActionRun } from "@w6w/sdk";

// Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
const client = new W6wClient();

const envelope = await client.run({
  urn: "conn_YOUR_CONNECTION_ID",
  action: "contact-create",
  payload: {
    first_name: "<value>",
    last_name: "<value>",
    email: "<value>",
    // cell_phone_1: "<value>",
    // home_phone: "<value>",
    // work_phone: "<value>",
    // fax: "<value>",
    // deal_type: "<value>",
    // primary_city: "<value>",
    // primary_state: "<value>",
    // primary_zip: "<value>",
    // primary_address: "<value>",
    // status: "<value>",
    // source: "<value>",
    // email_optin: "<value>",
    // phone_on: "<value>",
    // text_on: "<value>",
    // rating: "<value>",
    // capture_method: "<value>",
    // assigned_agent_id: "<value>",
    // assigned_agent_external_id: "<value>",
    // tcpa_optin_date: "<value>",
    // avg_price: "<value>",
    // avg_beds: "<value>",
    // avg_baths: "<value>",
    // is_private: "<value>",
    // active_mls_id: "<value>",
    // spouse_first_name: "<value>",
    // spouse_last_name: "<value>",
    // spouse_phone: "<value>",
    // spouse_title: "<value>",
    // title: "<value>",
    // birthday: "<value>",
    // gender: "<value>",
    // poi_address: "<value>",
    // poi_city: "<value>",
    // poi_state: "<value>",
    // poi_zip: "<value>",
    // second_email: "<value>",
    // external_vendor_id: "<value>",
    // last_closing_date: "<value>",
    // signup_mlsid: "<value>",
    // signup_mls: "<value>",
    // owned_by_assigned: "<value>",
    // entity_owner_id: "<value>",
    // hashtags: "<value>",
  },
});

if (isActionRun(envelope)) console.log(envelope.value);
Install the CLI
npm install -g @w6w/cli
CLI
w6w run conn_YOUR_CONNECTION_ID --action contact-create --payload '{"first_name":"<value>","last_name":"<value>","email":"<value>"}'

Give an AI agent kvCORE — without giving it kvCORE's credentials. One MCP endpoint exposes every app, function and workflow the caller is entitled to, as tools it can discover and run. Access is granted per team while we onboard.

One tool call
{
  "name": "w6w_invoke",
  "arguments": {
    "ref": "app:io.w6w.kvcore#contact-create",
    "input": {
      "first_name": "<first_name>",
      "last_name": "<last_name>",
      "email": "<email>"
    }
  }
}

Every tool names its target with a single ref. The app: form above doesn't name a connection at all — the host resolves which of the caller's kvCORE connections to sign with, and refuses rather than guesses when the answer is ambiguous.

What the agent gets

Credentials it can't read

The token is attached host-side, at the moment of the call. It is never a tool argument, never in the model's context, and never in a transcript — so a prompt injection has nothing to exfiltrate.

A tool surface scoped to the caller

Tools are derived per end user from what that person has actually connected and is entitled to — not one shared bot identity carrying the union of everyone's access.

A durable workflow in one call

Multi-step work runs on the workflow engine and returns a run handle the agent can poll — retries, branching and state survive the conversation that started them.

Health-aware discovery

kvCORE's declared health checks are on the surface too, so an agent can tell "the vendor is down" from "your credential expired" before it burns a retry on either.

The MCP surface is part of the hosted platform. kvCORE itself is MIT, and the runtime that executes it is source-available (FSL).

Request MCP access

Health checks

kvCORE declares its own checks, so its health is a property of the app rather than something the host guesses at.

service

kvCORE API status

Reads the "kvCORE API" component from status.insiderealestate.com — Inside Real Estate's shared Statuspage across its whole product line, scoped here to just the API component.

quota

Rate-limit headroom