Docs / Surface / contact-integration

Contact Integration

Surface integrates with Contact so you can screen message payloads for threats and trigger Strand workflows based on scan results.

How it works#

When a message arrives in Contact and matches a flow with tags, the flow system can trigger Strand workflows that include Surface scan steps. The tag-matching mechanism connects Contact messages to Strand workflows automatically:

  1. A message arrives at a Contact entity with tags (e.g. ["scan", "incoming"])
  2. Contact checks for Strand workflows whose trigger tags overlap with the message tags
  3. Any matching workflow is triggered with the message data as the workflow payload
  4. If the workflow includes a surface.platform node, the payload is scanned

The scan runs as part of the Strand workflow execution; it does not block or delay Contact message delivery.

Tag-matching mechanism#

Workflow triggering and connector routing match tags differently, and this is the most common integration mistake:

For example, a message tagged ["environmental", "data_quality"] does not fire a workflow whose trigger tags are only ["data_quality"], because that workflow is missing environmental. A workflow tagged ["environmental", "data_quality"] does fire for a message tagged ["data_quality"]. Keep message tags minimal and give workflows every tag they should respond to.

Contact trigger payload#

When Contact triggers a Strand workflow, the trigger payload has this structure:

json

{
  "payload": {
    "source": "contact",
    "contactFlow": {
      "flowId": "flow_abc",
      "flowName": "sensor_validation",
      "executionId": "exec_xyz"
    },
    "entity": {
      "id": "entities/temperature_sensor_01",
      "name": "temperature_sensor_01"
    },
    "messageId": "6614abcd1234ef5678901234",
    "tags": ["environmental", "data_quality"],
    "data": {
      "temperature": 85.2,
      "humidity": 45,
      "timestamp": "2025-03-24T10:00:00Z"
    },
    "timestamp": "2025-03-24T10:00:01Z",
    "trigger_depth": 0
  },
  "meta": {
    "account_id": "12345",
    "workflow_id": "6208953a_f5b1_46ae_8bfc_837054cece0f",
    "workflow_name": "sensor_validation",
    "trigger_source": "contact_flow",
    "triggered_at": "2025-03-24T10:00:01.412Z"
  }
}

Accessing fields in Strand workflows#

In Strand workflow nodes, the Contact trigger data is available via the data field in the payload. Because the trigger payload wraps the message data inside a data key, the actual message content is accessed as:

code

{{ payload.data }}

For example, to scan the message content in a Surface node:

code

{{ payload.data | tojson }}

To access specific fields from the original message:

code

{{ payload.data.temperature }}
{{ payload.entity.name }}
{{ payload.tags }}

Available trigger fields#

Field Type Description
payload.data object The actual message data payload
payload.tags array Tags that matched the trigger
payload.messageId string Contact message ID
payload.timestamp string ISO 8601 timestamp of the trigger
payload.entity.id string Entity resource path
payload.entity.name string Entity display name
payload.contactFlow.flowId string Contact flow ID that triggered
payload.contactFlow.flowName string Contact flow name
payload.contactFlow.executionId string Unique execution ID for this trigger
meta.account_id string Tendrl account ID

Setup#

Surface scanning in Contact runs through a Strand workflow that contains a Surface scan node. To set it up:

  1. In Strand, build a workflow with a Surface scan node (see Strand integration) and give the workflow trigger tags (e.g. ["scan"])
  2. Turn on Expose to Contact in that workflow's settings. A correctly tagged workflow that is not exposed never fires
  3. If you restrict the workflow's allowed sources, make sure the sending entity is on the list. An empty list means any entity
  4. In Contact, tag the messages you want screened, using only tags the workflow also has (the workflow's tags must cover every tag on the message)
  5. Matching messages automatically trigger the workflow, which scans the payload

No additional API key configuration is required; the platform handles authentication internally. Your account determines the monthly scan limit.

Scan result variables#

When a Strand workflow triggered from Contact includes a Surface scan node, the scan result fields are available for downstream conditions:

Variable Type Description
payload.threat_level string Clean, Informational, Suspicious, or Malicious, or Rejected / Error when nothing was scanned
payload.score integer 0-100 safety score (higher is safer)
payload.recommended_action string Allow, Review, or Block
payload.safe boolean true only when Surface scored the file and threat_level is not in reject_on. Never true for Rejected or Error
payload.primary_threat string Top matched threat label, or empty string
payload.request_id string Scan correlation ID
payload.iocs array Indicators of compromise
payload.coverage string full, partial or minimal — how far analysis reached for this format
payload.coverage_note string A sentence explaining that coverage level

Example branch condition#

code

{{ payload.threat_level == "Malicious" }}  ->  block or alert
{{ payload.safe == true }}                 ->  forward to downstream connector

Flow execution details#

In the Contact flow detail view, each step shows its result, including the Surface scan node's output: threat level, safety score (higher is safer), recommended action, and IOCs.

Limits#

Scans in Contact-triggered workflows count against your Surface monthly scan quota. When the quota is exhausted, payloads are forwarded without scanning; no messages are dropped.