Contacts (CRM)

Relationship layer — influencers, partners, candidates.

13 actions. Each is callable by the agent as a tool, over HTTP via /api/invoke, and (usually) from a UI page.

contacts.list

GET

List CRM contacts. Filter by type, stage, or owner.

  • AI tool: contacts_list
  • API: GET /api/invoke/contacts.list

Input

Field Type Required Description
type "influencer" | "partner" | "affiliate" | "press" | "candidate" | "vendor" | "fan" | "other"
stage string
ownerActorId string
limit integer
offset integer
orderBy string
orderDir "asc" | "desc"
q string
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "enum": [
        "influencer",
        "partner",
        "affiliate",
        "press",
        "candidate",
        "vendor",
        "fan",
        "other"
      ]
    },
    "stage": {
      "type": "string"
    },
    "ownerActorId": {
      "type": "string",
      "minLength": 1
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 500
    },
    "offset": {
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "orderBy": {
      "type": "string"
    },
    "orderDir": {
      "type": "string",
      "enum": [
        "asc",
        "desc"
      ]
    },
    "q": {
      "type": "string"
    }
  }
}

contacts.search

GET

Find contacts by name, handle, company, or tags.

  • AI tool: contacts_search
  • API: GET /api/invoke/contacts.search

Input

Field Type Required Description
q string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "q": {
      "type": "string"
    }
  },
  "required": [
    "q"
  ]
}

contacts.get

GET

Get one contact by id.

  • AI tool: contacts_get
  • API: GET /api/invoke/contacts.get

Input

Field Type Required Description
id string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "id"
  ]
}

contacts.create

POST · mutating

Create a CRM contact — someone you engage WITH (influencer, partner, journalist, candidate, vendor, fan), as opposed to a subject you post AS or promote.

When the agent calls it: Use when the user mentions an influencer, partner, journalist, candidate, vendor, or fan they want to track and reach out to. Pick the closest type. Do NOT create a subject for these — subjects are promotion targets. If the same person is also someone the user promotes or posts as, create the contact then call contacts.link_subject to connect it.

  • AI tool: contacts_create
  • API: POST /api/invoke/contacts.create

Input

Field Type Required Description
type "influencer" | "partner" | "affiliate" | "press" | "candidate" | "vendor" | "fan" | "other" yes
name string yes
handle string
avatarUrl string
company string
title string
headline string
bio string
location string
timezone string
tags string[]
stage string
ownerActorId union
source string
linkedSubjectId union
audience object
links object[]
customFields object
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "enum": [
        "influencer",
        "partner",
        "affiliate",
        "press",
        "candidate",
        "vendor",
        "fan",
        "other"
      ]
    },
    "name": {
      "type": "string"
    },
    "handle": {
      "type": "string"
    },
    "avatarUrl": {
      "type": "string"
    },
    "company": {
      "type": "string"
    },
    "title": {
      "type": "string"
    },
    "headline": {
      "type": "string"
    },
    "bio": {
      "type": "string"
    },
    "location": {
      "type": "string"
    },
    "timezone": {
      "type": "string"
    },
    "tags": {
      "default": [],
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "stage": {
      "default": "new",
      "type": "string"
    },
    "ownerActorId": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 1
        },
        {
          "type": "null"
        }
      ]
    },
    "source": {
      "default": "manual",
      "type": "string"
    },
    "linkedSubjectId": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 1
        },
        {
          "type": "null"
        }
      ]
    },
    "audience": {
      "default": {},
      "type": "object",
      "properties": {
        "totalReach": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991
        },
        "tier": {
          "type": "string",
          "enum": [
            "nano",
            "micro",
            "mid",
            "macro",
            "mega"
          ]
        },
        "score": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "byPlatform": {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {
            "type": "object",
            "properties": {
              "followers": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "engagementRate": {
                "type": "number"
              },
              "avgViews": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              }
            }
          }
        }
      }
    },
    "links": {
      "default": [],
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "github",
              "website",
              "twitter",
              "linkedin",
              "youtube",
              "instagram",
              "tiktok",
              "threads",
              "bluesky",
              "blog",
              "paper",
              "talk",
              "podcast",
              "document",
              "pdf",
              "other"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "label": {
            "type": "string"
          },
          "verified": {
            "type": "boolean"
          },
          "followers": {
            "type": "number"
          }
        },
        "required": [
          "type",
          "url"
        ]
      }
    },
    "customFields": {
      "default": {},
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "required": [
    "type",
    "name"
  ]
}

contacts.update

PATCH · mutating

Update fields on a contact (set stage to move it through the pipeline).

When the agent calls it: Advance the relationship by setting stage. Valid stages depend on the contact type.

  • AI tool: contacts_update
  • API: PATCH /api/invoke/contacts.update

Input

Field Type Required Description
id string yes
patch object yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    },
    "patch": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "type": {
          "type": "string",
          "enum": [
            "influencer",
            "partner",
            "affiliate",
            "press",
            "candidate",
            "vendor",
            "fan",
            "other"
          ]
        },
        "name": {
          "type": "string"
        },
        "handle": {
          "type": "string"
        },
        "avatarUrl": {
          "type": "string"
        },
        "company": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "headline": {
          "type": "string"
        },
        "bio": {
          "type": "string"
        },
        "location": {
          "type": "string"
        },
        "timezone": {
          "type": "string"
        },
        "tags": {
          "default": [],
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "stage": {
          "default": "new",
          "type": "string"
        },
        "ownerActorId": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1
            },
            {
              "type": "null"
            }
          ]
        },
        "source": {
          "default": "manual",
          "type": "string"
        },
        "linkedSubjectId": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1
            },
            {
              "type": "null"
            }
          ]
        },
        "convertedActorId": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1
            },
            {
              "type": "null"
            }
          ]
        },
        "audience": {
          "default": {},
          "type": "object",
          "properties": {
            "totalReach": {
              "type": "integer",
              "minimum": -9007199254740991,
              "maximum": 9007199254740991
            },
            "tier": {
              "type": "string",
              "enum": [
                "nano",
                "micro",
                "mid",
                "macro",
                "mega"
              ]
            },
            "score": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            },
            "byPlatform": {
              "type": "object",
              "propertyNames": {
                "type": "string"
              },
              "additionalProperties": {
                "type": "object",
                "properties": {
                  "followers": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "engagementRate": {
                    "type": "number"
                  },
                  "avgViews": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  }
                }
              }
            }
          }
        },
        "totalReach": {
          "anyOf": [
            {
              "type": "integer",
              "minimum": -9007199254740991,
              "maximum": 9007199254740991
            },
            {
              "type": "null"
            }
          ]
        },
        "links": {
          "default": [],
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "github",
                  "website",
                  "twitter",
                  "linkedin",
                  "youtube",
                  "instagram",
                  "tiktok",
                  "threads",
                  "bluesky",
                  "blog",
                  "paper",
                  "talk",
                  "podcast",
                  "document",
                  "pdf",
                  "other"
                ]
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "label": {
                "type": "string"
              },
              "verified": {
                "type": "boolean"
              },
              "followers": {
                "type": "number"
              }
            },
            "required": [
              "type",
              "url"
            ]
          }
        },
        "customFields": {
          "default": {},
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        },
        "lastInteractionAt": {
          "anyOf": [
            {},
            {
              "type": "null"
            }
          ]
        },
        "createdBy": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1
            },
            {
              "type": "null"
            }
          ]
        },
        "createdAt": {},
        "updatedAt": {}
      }
    }
  },
  "required": [
    "id",
    "patch"
  ]
}

contacts.delete

DELETE · mutating

Soft-delete a contact. Reversible via contacts.restore.

  • AI tool: contacts_delete
  • API: DELETE /api/invoke/contacts.delete

Input

Field Type Required Description
id string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "id"
  ]
}

contacts.restore

POST · mutating

Restore a soft-deleted contact.

  • AI tool: contacts_restore
  • API: POST /api/invoke/contacts.restore

Input

Field Type Required Description
id string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "id"
  ]
}

contacts.timeline

GET

Get a contact's activity timeline — inbound engagements, DM threads, calls, outreach tickets, and notes merged in time order. Keyset-paginate with before.

  • AI tool: contacts_timeline
  • API: GET /api/invoke/contacts.timeline

Input

Field Type Required Description
contactId string yes
limit integer
before any
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "contactId": {
      "type": "string",
      "minLength": 1
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    },
    "before": {}
  },
  "required": [
    "contactId"
  ]
}

contacts.send_outreach

POST · mutating

Send an outreach DM to a contact via the cross-platform DM router. Resolves the recipient from the contact's channels, mirrors the thread, links it to the contact, logs it, and advances an early-stage relationship to "contacted".

When the agent calls it: Use to reach out to a contact. For SMS, also set fromPhoneNumberId. Works in simulated mode when no provider is connected.

  • AI tool: contacts_send_outreach
  • API: POST /api/invoke/contacts.send_outreach

Input

Field Type Required Description
contactId string yes
platform "twitter" | "linkedin" | "instagram" | "slack" | "discord" | "sms" yes
body string yes
fromSubjectId string
actorId string
fromPhoneNumberId string
composioUserId string
advanceStage boolean
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "contactId": {
      "type": "string",
      "minLength": 1
    },
    "platform": {
      "type": "string",
      "enum": [
        "twitter",
        "linkedin",
        "instagram",
        "slack",
        "discord",
        "sms"
      ]
    },
    "body": {
      "type": "string",
      "minLength": 1
    },
    "fromSubjectId": {
      "type": "string",
      "minLength": 1
    },
    "actorId": {
      "type": "string",
      "minLength": 1
    },
    "fromPhoneNumberId": {
      "type": "string",
      "minLength": 1
    },
    "composioUserId": {
      "type": "string"
    },
    "advanceStage": {
      "type": "boolean"
    }
  },
  "required": [
    "contactId",
    "platform",
    "body"
  ]
}

contacts.list_send_accounts

GET

List the subject/persona accounts that can SEND — subjects with an active Stagehand browser session or a usable Composio connection. Each account is tied to a platform (the account IS the platform choice). Pass platform to filter to one. Powers the "Send from" picker for outreach.

  • AI tool: contacts_list_send_accounts
  • API: GET /api/invoke/contacts.list_send_accounts

Input

Field Type Required Description
platform string
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "platform": {
      "type": "string"
    }
  }
}

contacts.convert_to_actor

POST · mutating

Convert a candidate-type contact into an Actor (a hire / new persona-driver). Creates the actor, links contact.convertedActorId, and advances the contact to "onboarded". Idempotent.

When the agent calls it: Only for type="candidate". Use after the user decides to hire/onboard the person.

  • AI tool: contacts_convert_to_actor
  • API: POST /api/invoke/contacts.convert_to_actor

Input

Field Type Required Description
contactId string yes
kind "human" | "agent"
sendWelcomeDm boolean
welcomeBody string
welcomePlatform "twitter" | "linkedin" | "instagram" | "slack" | "discord" | "sms"
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "contactId": {
      "type": "string",
      "minLength": 1
    },
    "kind": {
      "type": "string",
      "enum": [
        "human",
        "agent"
      ]
    },
    "sendWelcomeDm": {
      "type": "boolean"
    },
    "welcomeBody": {
      "type": "string"
    },
    "welcomePlatform": {
      "type": "string",
      "enum": [
        "twitter",
        "linkedin",
        "instagram",
        "slack",
        "discord",
        "sms"
      ]
    }
  },
  "required": [
    "contactId"
  ]
}

POST · mutating

Link (or unlink, with subjectId=null) a contact to a Subject — for someone you both court (contact) and promote/post-as (subject).

  • AI tool: contacts_link_subject
  • API: POST /api/invoke/contacts.link_subject

Input

Field Type Required Description
id string yes
subjectId union yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    },
    "subjectId": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 1
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "id",
    "subjectId"
  ]
}

contacts.create_from_subject

POST · mutating

Create a CRM contact prefilled from an existing subject and link them. Use to move a relationship-style person (an influencer, partner, recruit) OUT of the subjects list into the CRM without losing the subject or its missions.

When the agent calls it: Use when the user realizes a person they created as a subject is really a relationship to manage (not something they post as). Keeps the subject; links it.

  • AI tool: contacts_create_from_subject
  • API: POST /api/invoke/contacts.create_from_subject

Input

Field Type Required Description
subjectId string yes
type "influencer" | "partner" | "affiliate" | "press" | "candidate" | "vendor" | "fan" | "other"
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "subjectId": {
      "type": "string",
      "minLength": 1
    },
    "type": {
      "type": "string",
      "enum": [
        "influencer",
        "partner",
        "affiliate",
        "press",
        "candidate",
        "vendor",
        "fan",
        "other"
      ]
    }
  },
  "required": [
    "subjectId"
  ]
}