← capabilitiescrm.write

log_activity

crm.log_activity · v0.1.0

Record a touchpoint (call, email, meeting, note) against an existing contact on a CRM tenant.

Semantics

Appends an activity row to the contact's timeline. The contact is identified by their email address, which is resolved against the tenant's contact list. If the email belongs to a contact on a different tenant inside the same CRM, the call returns `wrong_tenant` with a hint pointing at the correct provider_id so the agent can retry without round-tripping the user.

Invariants

  • Append-only. Activities cannot be edited or deleted via this capability.
  • The contact must exist for the call to succeed. To create a new contact use `crm.create_contact` first.
  • Activity kind must be one of: `call`, `email`, `meeting`, `note`, `task`.
  • `occurred_at` is normalised to UTC; if omitted, the server uses receive-time.

When to use

After the user has had a real interaction with a contact, to keep the CRM timeline current. Call this *after* the conversation/event, not before.

Input schema

{
  "type": "object",
  "required": [
    "contact_email",
    "kind",
    "summary"
  ],
  "properties": {
    "kind": {
      "enum": [
        "call",
        "email",
        "meeting",
        "note",
        "task"
      ],
      "type": "string"
    },
    "summary": {
      "type": "string",
      "maxLength": 2000,
      "minLength": 1,
      "description": "Free-text summary of what was discussed or done."
    },
    "occurred_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the interaction happened. Defaults to now."
    },
    "agent_vendor": {
      "type": "string"
    },
    "contact_email": {
      "type": "string",
      "format": "email",
      "description": "Email of the existing contact on this tenant. Used as the resolution key."
    },
    "duration_minutes": {
      "type": "number",
      "minimum": 0,
      "description": "Optional duration in minutes for calls and meetings."
    }
  },
  "additionalProperties": false
}

Output schema

{
  "type": "object",
  "required": [
    "ok"
  ],
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "error": {
      "enum": [
        "unknown_contact",
        "wrong_tenant",
        "invalid_input"
      ],
      "type": "string"
    },
    "contact": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "email": {
          "type": "string"
        }
      }
    },
    "activity_id": {
      "type": "string"
    },
    "occurred_at": {
      "type": "string",
      "format": "date-time"
    },
    "wrong_tenant_hint": {
      "type": "object",
      "properties": {
        "matched_provider_id": {
          "type": "string"
        }
      }
    }
  }
}

Recent conformance runs

passprovidertestmswhen
crm:dental-pro-pdxrejects_invalid_kind005-18 19:51
crm:dental-pro-pdxrejects_unknown_contact24505-18 19:51
crm:dental-pro-pdxhappy_path21905-18 19:51
crm:acme-consulting-brooklynrejects_invalid_kind005-18 19:51
crm:acme-consulting-brooklynrejects_unknown_contact17405-18 19:51
crm:acme-consulting-brooklynhappy_path20605-18 19:51
crm:design-shop-austinrejects_invalid_kind105-18 19:51
crm:design-shop-austinrejects_unknown_contact15505-18 19:51
crm:design-shop-austinhappy_path156405-18 19:51