For the complete documentation index, see llms.txt. This page is also available as Markdown.

Surfaces

Agent-generated data collection interfaces: SurfaceSpec, fields, channels, lifecycle, and submission handling.

Surfaces are agent-generated data collection interfaces delivered to patients through supported communication channels. Agents analyze entity state and data gaps in the world model, generate a SurfaceSpec, and the platform renders and delivers it. Submissions return as source-attributed world-model events; any later external delivery follows a separate connector policy.

Conceptual overview. For the architecture, healthcare examples, and design rationale, see Surfaces in the conceptual docs.

Voice Agent Surface Tools

A family of context graph tools allows voice agents to create and manage surfaces during live calls:

Tool
Parameters
Returns

create_surface

entity_id (required), title (required), fields (required, list), description, channel, expires_in_hours, resource_type, context

surface_id, url, status, expires_at

create_surface_from_template

template_id (required), entity_id (required)

surface_id, url, status, prefilled_count, total_fields. Resolves a form template against the patient's entity state, prefilling fields with known data.

get_form_templates

optional category, patient_type filters

Reusable form templates for the workspace

deliver_surface

surface_id (required), channel_address (required: phone number or email)

surface_id, url, status

check_surface_status

surface_id (required)

surface_id, status, title, fields_count, entity_id, created_at

get_surface_progress

surface_id (required)

Field-level completion status (which fields are filled vs empty)

reshape_surface

surface_id (required)

New surface_id and url containing only the unfilled fields from an abandoned form

list_entity_surfaces

entity_id (required), status (optional filter)

surfaces[] (id, title, status, channel, created_at), count

get_surface_insights

entity_id (required)

entity_id, completion_rate, preferred_channel, total_surfaces, completed, pending_surfaces, recent_surfaces[]

extract_surface_file_text

surface_id (required)

Readable text extracted from submitted PDF file fields

get_surface_insights queries the entity's surface analytics before creating new surfaces. Returns completion rate, preferred channel, and count of pending (unfinished) surfaces. Call this before create_surface to avoid surface fatigue: if a patient already has multiple pending surfaces or a low completion rate, the agent may choose to collect data verbally instead.

These tools proxy through the Platform API surface endpoints. Authentication uses the call's agent_session JWT, which is workspace-scoped, so surface operations are automatically isolated to the correct workspace.

All of these tools handle errors gracefully: if the Platform API is unreachable, the agent receives an error message rather than an exception, so it can continue the call.

Permissions

Two scopes control surface access:

Scope
Grants

surfaces:read

View surface specs, submissions, and lifecycle status

surfaces:write

Generate new surface specs

Both scopes are included in the member role by default. RBAC enforcement is applied on all surface CRUD routes (view, create, update, delete).

Management API

Create a Surface

Create Surface

post

Create a new data collection surface.

Stores the surface spec as a world.event with domain="surface". The entity_id is stored inside event data (not on the event row) to avoid entity state recomputation.

Returns a signed patient-facing token and URL if SURFACE_TOKEN_SECRET is configured.

Permissions: member, admin, owner (surfaces:write)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Body

Request to create a new surface.

The agent generates a SurfaceSpec and sends it here.

entity_idstring · uuidRequired
titlestring · min: 1 · max: 256Required
descriptionstring · max: 2000 · nullableOptional
channelstring · enumOptional

Delivery channels for surfaces.

Default: webPossible values:
use_case_idstring · uuid · nullableOptional
expires_in_hoursinteger · min: 1 · max: 8760OptionalDefault: 168
resource_typestring · max: 64 · nullableOptional
completion_titlestring · max: 256 · nullableOptional
completion_messagestring · max: 2000 · nullableOptional
completion_action_urlstring · max: 2048 · nullableOptional
submit_button_textstring · max: 128 · nullableOptional
Responses
200

Successful Response

application/json
idstring · uuidRequired
event_idstring · uuidRequired
entity_idstring · uuidRequired
titlestringRequired
descriptionstring · nullableOptional
statusstring · enumRequired

Lifecycle status of a surface.

Possible values:
channelstring · enumRequired

Delivery channels for surfaces.

Possible values:
use_case_idstring · uuid · nullableOptional
fields_countintegerRequired
expires_atstringRequired
created_atstringRequired
tokenstring · nullableOptional
urlstring · nullableOptional
post/v1/{workspace_id}/surfaces
POST /v1/{workspace_id}/surfaces HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 892

{
  "entity_id": "123e4567-e89b-12d3-a456-426614174000",
  "title": "text",
  "description": "text",
  "fields": [
    {
      "key": "text",
      "label": "text",
      "field_type": "text",
      "required": true,
      "options": [
        "text"
      ],
      "description": "text",
      "placeholder": "text",
      "prefill_value": null,
      "validation": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "sensitive": false,
      "condition": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "consent_text": "text"
    }
  ],
  "channel": "web",
  "use_case_id": "123e4567-e89b-12d3-a456-426614174000",
  "expires_in_hours": 168,
  "context": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "resource_type": "text",
  "branding": {
    "logo_url": "text",
    "primary_color": "text",
    "background_color": "text",
    "font_family": "text"
  },
  "sections": [
    {
      "title": "text",
      "description": "text",
      "field_keys": [
        "text"
      ],
      "condition": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      }
    }
  ],
  "completion_title": "text",
  "completion_message": "text",
  "completion_action_url": "text",
  "submit_button_text": "text"
}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "event_id": "123e4567-e89b-12d3-a456-426614174000",
  "entity_id": "123e4567-e89b-12d3-a456-426614174000",
  "title": "text",
  "description": "text",
  "status": "created",
  "channel": "email",
  "use_case_id": "123e4567-e89b-12d3-a456-426614174000",
  "fields_count": 1,
  "expires_at": "text",
  "created_at": "text",
  "token": "text",
  "url": "text"
}

List Surfaces

List Surfaces

get

List surfaces with pagination and optional filters.

Permissions: viewer, member, admin, owner (surfaces:read)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Query parameters
limitinteger · max: 200OptionalDefault: 50
continuation_tokenanyOptional
entity_idstring · uuid · nullableOptional

Filter by entity ID

statusstring · nullableOptional

Filter by status

channelstring · nullableOptional

Filter by channel

Responses
200

Successful Response

application/json
has_morebooleanRequired
continuation_tokenanyOptional
get/v1/{workspace_id}/surfaces
GET /v1/{workspace_id}/surfaces HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "items": [
    {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "event_id": "123e4567-e89b-12d3-a456-426614174000",
      "entity_id": "123e4567-e89b-12d3-a456-426614174000",
      "title": "text",
      "description": "text",
      "status": "created",
      "channel": "email",
      "use_case_id": "123e4567-e89b-12d3-a456-426614174000",
      "fields_count": 1,
      "fields": [
        {
          "ANY_ADDITIONAL_PROPERTY": "anything"
        }
      ],
      "resource_type": "text",
      "context": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "expires_at": "text",
      "created_at": "text",
      "delivered_at": "text",
      "opened_at": "text",
      "submitted_at": "text",
      "submitted_data": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "delivery_metadata": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "review_notes": "text",
      "reviewed_by": "123e4567-e89b-12d3-a456-426614174000",
      "reviewed_at": "text",
      "archived_at": "text",
      "archive_reason": "text",
      "url": "text"
    }
  ],
  "has_more": true,
  "continuation_token": null
}

Get a Surface

Get Surface

get

Get a surface by ID.

Returns the surface spec and current lifecycle status. Also mints the patient-facing url so operators can copy/share the link from the read view (the token isn't stored, so it's re-minted on each read).

Permissions: viewer, member, admin, owner (surfaces:read)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Responses
200

Successful Response

application/json
idstring · uuidRequired
event_idstring · uuidRequired
entity_idstring · uuid · nullableOptional
titlestring · nullableOptional
descriptionstring · nullableOptional
statusstring · enumRequired

Lifecycle status of a surface.

Possible values:
channelstring · enum · nullableOptional

Delivery channels for surfaces.

Possible values:
use_case_idstring · uuid · nullableOptional
fields_countintegerRequired
resource_typestring · nullableOptional
expires_atstring · nullableOptional
created_atstring · nullableOptional
delivered_atstring · nullableOptional
opened_atstring · nullableOptional
submitted_atstring · nullableOptional
review_notesstring · nullableOptional
reviewed_bystring · uuid · nullableOptional
reviewed_atstring · nullableOptional
archived_atstring · nullableOptional
archive_reasonstring · nullableOptional
urlstring · nullableOptional
get/v1/{workspace_id}/surfaces/{surface_id}
GET /v1/{workspace_id}/surfaces/{surface_id} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "event_id": "123e4567-e89b-12d3-a456-426614174000",
  "entity_id": "123e4567-e89b-12d3-a456-426614174000",
  "title": "text",
  "description": "text",
  "status": "created",
  "channel": "email",
  "use_case_id": "123e4567-e89b-12d3-a456-426614174000",
  "fields_count": 1,
  "fields": [
    {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    }
  ],
  "resource_type": "text",
  "context": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "expires_at": "text",
  "created_at": "text",
  "delivered_at": "text",
  "opened_at": "text",
  "submitted_at": "text",
  "submitted_data": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "delivery_metadata": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "review_notes": "text",
  "reviewed_by": "123e4567-e89b-12d3-a456-426614174000",
  "reviewed_at": "text",
  "archived_at": "text",
  "archive_reason": "text",
  "url": "text"
}

Update a Surface

Update a surface spec

patch

Update an existing surface spec.

Only allowed while status is CREATED or DELIVERED. Writes a surface.updated event preserving the full audit trail.

Permissions: member, admin, owner (Surface:Create)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Body

Partial update to an existing surface.

All fields are optional. Only provided fields are merged into the spec. Only allowed while status is CREATED or DELIVERED.

titlestring · min: 1 · max: 256 · nullableOptional
descriptionstring · max: 2000 · nullableOptional
completion_titlestring · max: 256 · nullableOptional
completion_messagestring · max: 2000 · nullableOptional
completion_action_urlstring · max: 2048 · nullableOptional
submit_button_textstring · max: 128 · nullableOptional
channelstring · enum · nullableOptional

Delivery channels for surfaces.

Possible values:
resource_typestring · max: 64 · nullableOptional
Responses
200

Successful Response

application/json
idstring · uuidRequired
event_idstring · uuidRequired
entity_idstring · uuid · nullableOptional
titlestring · nullableOptional
descriptionstring · nullableOptional
statusstring · enumRequired

Lifecycle status of a surface.

Possible values:
channelstring · enum · nullableOptional

Delivery channels for surfaces.

Possible values:
use_case_idstring · uuid · nullableOptional
fields_countintegerRequired
resource_typestring · nullableOptional
expires_atstring · nullableOptional
created_atstring · nullableOptional
delivered_atstring · nullableOptional
opened_atstring · nullableOptional
submitted_atstring · nullableOptional
review_notesstring · nullableOptional
reviewed_bystring · uuid · nullableOptional
reviewed_atstring · nullableOptional
archived_atstring · nullableOptional
archive_reasonstring · nullableOptional
urlstring · nullableOptional
patch/v1/{workspace_id}/surfaces/{surface_id}
PATCH /v1/{workspace_id}/surfaces/{surface_id} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 718

{
  "title": "text",
  "description": "text",
  "fields": [
    {
      "key": "text",
      "label": "text",
      "field_type": "text",
      "required": true,
      "options": [
        "text"
      ],
      "description": "text",
      "placeholder": "text",
      "prefill_value": null,
      "validation": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "sensitive": false,
      "condition": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "consent_text": "text"
    }
  ],
  "branding": {
    "logo_url": "text",
    "primary_color": "text",
    "background_color": "text",
    "font_family": "text"
  },
  "sections": [
    {
      "title": "text",
      "description": "text",
      "field_keys": [
        "text"
      ],
      "condition": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      }
    }
  ],
  "completion_title": "text",
  "completion_message": "text",
  "completion_action_url": "text",
  "submit_button_text": "text",
  "channel": "email",
  "resource_type": "text"
}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "event_id": "123e4567-e89b-12d3-a456-426614174000",
  "entity_id": "123e4567-e89b-12d3-a456-426614174000",
  "title": "text",
  "description": "text",
  "status": "created",
  "channel": "email",
  "use_case_id": "123e4567-e89b-12d3-a456-426614174000",
  "fields_count": 1,
  "fields": [
    {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    }
  ],
  "resource_type": "text",
  "context": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "expires_at": "text",
  "created_at": "text",
  "delivered_at": "text",
  "opened_at": "text",
  "submitted_at": "text",
  "submitted_data": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "delivery_metadata": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "review_notes": "text",
  "reviewed_by": "123e4567-e89b-12d3-a456-426614174000",
  "reviewed_at": "text",
  "archived_at": "text",
  "archive_reason": "text",
  "url": "text"
}

Archive a Surface

Archive (soft-delete) a surface

delete

Archive (soft-delete) a surface.

Works for any non-terminal surface. Terminal surfaces (completed, expired, already archived) cannot be archived.

Permissions: member, admin, owner (Surface:Create)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Responses
200

Successful Response

application/json
surface_idstring · uuidRequired
statusconst: archivedRequired
delete/v1/{workspace_id}/surfaces/{surface_id}
DELETE /v1/{workspace_id}/surfaces/{surface_id} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "surface_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "text"
}

List Surfaces Pending Review

List surfaces pending review

get

List surfaces pending review.

Field engineers use this to approve or reject surfaces before delivery.

Permissions: operator, member, admin, owner (ReviewQueue:View)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Query parameters
limitinteger · max: 200OptionalDefault: 50
continuation_tokenanyOptional
Responses
200

Successful Response

application/json
has_morebooleanRequired
continuation_tokenanyOptional
get/v1/{workspace_id}/surfaces/review
GET /v1/{workspace_id}/surfaces/review HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "items": [
    {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "event_id": "123e4567-e89b-12d3-a456-426614174000",
      "entity_id": "123e4567-e89b-12d3-a456-426614174000",
      "title": "text",
      "description": "text",
      "status": "created",
      "channel": "email",
      "use_case_id": "123e4567-e89b-12d3-a456-426614174000",
      "fields_count": 1,
      "fields": [
        {
          "ANY_ADDITIONAL_PROPERTY": "anything"
        }
      ],
      "resource_type": "text",
      "context": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "expires_at": "text",
      "created_at": "text",
      "delivered_at": "text",
      "opened_at": "text",
      "submitted_at": "text",
      "submitted_data": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "delivery_metadata": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "review_notes": "text",
      "reviewed_by": "123e4567-e89b-12d3-a456-426614174000",
      "reviewed_at": "text",
      "archived_at": "text",
      "archive_reason": "text",
      "url": "text"
    }
  ],
  "has_more": true,
  "continuation_token": null
}

Approve a Surface

Approve a surface pending review

post

Approve a surface pending review.

The surface returns to CREATED status and can then be delivered.

Permissions: operator, member, admin, owner (ReviewQueue:Review)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Responses
200

Successful Response

application/json
surface_idstring · uuidRequired
statusstring · enumRequired

Lifecycle status of a surface.

Possible values:
actionstring · enumRequiredPossible values:
post/v1/{workspace_id}/surfaces/{surface_id}/approve
POST /v1/{workspace_id}/surfaces/{surface_id}/approve HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "surface_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "created",
  "action": "approved"
}

Reject a Surface

Reject a surface pending review

post

Reject a surface pending review.

The surface is marked as expired and will not be delivered.

Permissions: operator, member, admin, owner (ReviewQueue:Review)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Body
reasonstring · max: 2000 · nullableOptional
Responses
200

Successful Response

application/json
surface_idstring · uuidRequired
statusstring · enumRequired

Lifecycle status of a surface.

Possible values:
actionstring · enumRequiredPossible values:
post/v1/{workspace_id}/surfaces/{surface_id}/reject
POST /v1/{workspace_id}/surfaces/{surface_id}/reject HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 17

{
  "reason": "text"
}
{
  "surface_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "created",
  "action": "approved"
}

Reshape a Surface

Create new surface with only unfilled fields

post

Create a new surface with only the unfilled fields from the original.

Used for re-engaging patients who abandoned a form. The new surface contains only the fields they haven't completed yet, reducing friction.

Permissions: member, admin, owner (surfaces:write)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Responses
200

Successful Response

application/json
idstring · uuidRequired
event_idstring · uuidRequired
entity_idstring · uuidRequired
titlestringRequired
descriptionstring · nullableOptional
statusstring · enumRequired

Lifecycle status of a surface.

Possible values:
channelstring · enumRequired

Delivery channels for surfaces.

Possible values:
use_case_idstring · uuid · nullableOptional
fields_countintegerRequired
expires_atstringRequired
created_atstringRequired
tokenstring · nullableOptional
urlstring · nullableOptional
post/v1/{workspace_id}/surfaces/{surface_id}/reshape
POST /v1/{workspace_id}/surfaces/{surface_id}/reshape HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "event_id": "123e4567-e89b-12d3-a456-426614174000",
  "entity_id": "123e4567-e89b-12d3-a456-426614174000",
  "title": "text",
  "description": "text",
  "status": "created",
  "channel": "email",
  "use_case_id": "123e4567-e89b-12d3-a456-426614174000",
  "fields_count": 1,
  "expires_at": "text",
  "created_at": "text",
  "token": "text",
  "url": "text"
}

Get Surface Progress

Get field-level completion status

get

Get field-level completion status for a surface.

Returns which fields are filled vs empty, useful for abandonment intelligence and targeted re-engagement.

Permissions: viewer, member, admin, owner (surfaces:read)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Responses
200

Successful Response

application/json
surface_idstring · uuidRequired
total_fieldsintegerRequired
filled_countintegerRequired
empty_countintegerRequired
filled_keysstring[]Required
empty_keysstring[]Required
required_empty_keysstring[]Required
get/v1/{workspace_id}/surfaces/{surface_id}/progress
GET /v1/{workspace_id}/surfaces/{surface_id}/progress HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "surface_id": "123e4567-e89b-12d3-a456-426614174000",
  "total_fields": 1,
  "filled_count": 1,
  "empty_count": 1,
  "filled_keys": [
    "text"
  ],
  "empty_keys": [
    "text"
  ],
  "required_empty_keys": [
    "text"
  ]
}

Deliver a Surface

Deliver Surface

post

Record a real delivery handoff for a surface.

Email targets are delivered through channel-manager's POST /v1/email/ (CM owns SES sender identity, IP pool, DKIM, suppression — keyed on the surface row's use_case_id). Phone-shaped addresses return 422 — SMS surface delivery was removed in PR #2783. Other targets record an external handoff that was completed outside platform-api.

Permissions: member, admin, owner (surfaces:write)

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
surface_idstring · uuidRequired
Body

Request to mark a surface as delivered.

channel_addressstring · min: 1 · max: 256Required

Delivery address (phone number, email, etc.)

Responses
200

Successful Response

application/json
surface_idstring · uuidRequired
statusstring · enumRequiredPossible values:
channelstring · enum · nullableOptional

Delivery channels for surfaces.

Possible values:
urlstring · nullableOptional
channel_addressstringRequired
message_idstring · nullableOptional
from_numberstring · nullableOptional
from_addressstring · nullableOptional
delivery_providerstring · nullableOptional
delivered_atstring · nullableOptional
post/v1/{workspace_id}/surfaces/{surface_id}/deliver
POST /v1/{workspace_id}/surfaces/{surface_id}/deliver HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 26

{
  "channel_address": "text"
}
{
  "surface_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "delivered",
  "channel": "email",
  "url": "text",
  "channel_address": "text",
  "message_id": "text",
  "from_number": "text",
  "from_address": "text",
  "delivery_provider": "text",
  "delivered_at": "text"
}

The delivery endpoint sends the surface URL to the patient, marks the surface as delivered, writes an audit event, and publishes a surface.delivered SSE event for real-time dashboards.

Delivery behavior: email-shaped delivery targets are sent through the workspace's configured email transport (the surface must have been created with channel='email' and a bound use_case_id). The email body contains a short redirect link (/s/f/{surface_id}) that 302-redirects to the full signed token URL. Non-email, non-phone targets record a web handoff. Phone-number targets are rejected with 422.

Error responses: the deliver endpoint returns 404 (surface not found), 409 (already delivered/completed/expired, or test surface), 422 (validation, including a rejected phone target), and 429 (rate limited). Email delivery additionally returns 503 when email transport is not configured.

Lifecycle SSE events: surface.delivered, surface.opened, surface.submitted are published in real time as they happen.

Surface expiry: Non-terminal surfaces (not yet completed) automatically expire after their configured TTL. Expired surfaces reject renders, submissions, and auto-saves.

Channels

Channel
Value
Delivery Method

Email

email

Email with branded link

Web

web

Direct link for portals or dashboards

SMS

sms

Spec value only - link delivery is not supported (returns 422); use email or web

While sms is a valid channel value on a spec, the deliver endpoint does not support SMS link delivery (phone-shaped addresses return 422). Delivery is email or web.

BrandingConfig

Visual branding applied to the patient-facing form. Can be set at workspace level (default for all surfaces) or per-surface (overrides workspace defaults).

Get Workspace Branding

Get workspace branding

get

Get the workspace default branding for surfaces.

Returns empty branding when not configured.

Permissions: authenticated (any role).

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Responses
200

Successful Response

application/json
get/v1/{workspace_id}/settings/branding
GET /v1/{workspace_id}/settings/branding HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "branding": {
    "logo_url": "text",
    "primary_color": "text",
    "background_color": "text",
    "font_family": "text"
  }
}

Update Workspace Branding

Update workspace branding

put

Update the workspace default branding for surfaces.

Surface-level branding takes precedence over workspace-level branding.

Permissions: admin, owner.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Body

Update workspace branding. All fields are optional — only provided fields are changed.

Responses
200

Successful Response

application/json
put/v1/{workspace_id}/settings/branding
PUT /v1/{workspace_id}/settings/branding HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 102

{
  "branding": {
    "logo_url": "text",
    "primary_color": "text",
    "background_color": "text",
    "font_family": "text"
  }
}
{
  "branding": {
    "logo_url": "text",
    "primary_color": "text",
    "background_color": "text",
    "font_family": "text"
  }
}

When rendering a surface, the platform merges workspace branding with surface-level branding. Surface-level values take precedence. Changes to workspace branding are audit-logged.

Lifecycle

Status
Value
Description

Created

created

Spec generated and stored

Pending review

pending_review

Surface awaiting field-engineer review before delivery

Delivered

delivered

Sent to patient via channel

Opened

opened

Patient opened the link

Partial

partial

Some fields auto-saved

Completed

completed

All required fields submitted

Expired

expired

TTL exceeded without completion

Archived

archived

Soft-deleted via the DELETE/archive route

Data Flow

Submissions are written to the world model as events:

  • Source: surface (distinguishable from EHR, voice, or manual imports)

  • Confidence: Initial confidence level for patient-reported data

  • Entity: Emitted lifecycle events carry the surface's entity_id, allowing supported world-model projections and timelines to associate them with that entity

When a patient submits a surface, the platform first commits the surface row as completed. It then schedules surface.submitted world-event emission asynchronously on a best-effort path. Timeline and entity projection updates therefore happen separately and can lag the successful submission response; an emission failure is logged rather than rolling back the committed surface.

An emitted surface event retains source provenance and confidence. Any later entity resolution or typed projection depends on the downstream pipeline for that event shape rather than a universal synchronous rule. Where the private-preview connector review flow is enabled, a configured downstream mutation can stage a separate external write proposal; reviewing that proposal does not change the surface event's confidence.

Patient-Facing Endpoints

Patients access surfaces through HMAC-signed URL tokens. No login or account is required, and each token grants access to one specific surface.

Redirect To Surface

get

Short-URL redirect: /s/f/{surface_id} → /s/{token}.

Generates a fresh HMAC token and issues a 302 redirect so that SMS messages can contain a short, clickable link instead of the long base64-encoded token URL.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
surface_idstring · uuidRequired
Responses
200

Successful Response

application/json
anyOptional
get/s/f/{surface_id}
GET /s/f/{surface_id} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*

No content

Render a Surface

Render Surface

get

Render a patient-facing surface as HTML.

Token-authenticated — no Bearer auth required. Records a surface.opened lifecycle event on first view.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
tokenstringRequired
Responses
200

Successful Response

application/json
anyOptional
get/s/{token}
GET /s/{token} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*

No content

Submit a Surface

Submit Surface

post

Submit a patient-facing surface form.

Accepts standard HTML form POST. Writes surface.submitted event with confidence 0.5 (self-reported data).

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
tokenstringRequired
Responses
200

Successful Response

application/json
anyOptional
post/s/{token}/submit
POST /s/{token}/submit HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*

No content

Save a Surface Field

Save Field

put

Auto-save a single field value.

Called by client-side JavaScript on field blur. Writes surface.field_saved event with confidence 0.5.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
tokenstringRequired
keystringRequired
Body
valueanyRequired

The field value to save

Responses
200

Successful Response

application/json

Acknowledgement returned when a field is auto-saved.

statusconst: savedOptionalDefault: saved
put/s/{token}/fields/{key}
PUT /s/{token}/fields/{key} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 14

{
  "value": null
}
{
  "status": "saved"
}

The short-link operation issues a redirect to a fresh signed-token URL and reports missing or expired surfaces separately. Rendering marks the surface as opened. Submission commits the completed surface before scheduling best-effort world-event publication. Field saves update the lifecycle to partial.

Token format: HMAC-SHA256 signed with a configured secret. Contains surface ID and expiration. Validated on every request.

Rate limiting (per IP):

  • Render: 30 requests/minute

  • Submit: 10 requests/minute

  • Auto-save: 30 requests/minute

Field value validation: Individual field values are capped at 10KB to prevent payload abuse.

Rendering: server-side HTML generation for all 14 field types. Mobile-first, XSS-safe. Photo and file uploads use native device capabilities. Signature fields use touch input.

Lifecycle concurrency: each status update is committed against the surface row. Submission locks the row while checking terminal state and marking it completed, which rejects a competing repeat submission. World-event emission is outside that transaction.

When creating a surface via the management API, the response includes the signed token and full url if the token secret is configured.

Gap Scanner Settings

Get Gap Scanner Settings

Update Gap Scanner Settings

Updates require an admin or owner and support partial bodies. Changes to settings are audit-logged.

Surface Analytics

These workspace-scoped operations provide closed-loop optimization data and require viewer-or-higher permissions.

Get Surface Completion Rates

Surface Completion Rates

get

Surface completion rates: overall, by source, time-bucketed trend.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Query parameters
daysinteger · min: 1 · max: 90OptionalDefault: 30
date_fromstring · date · nullableOptional
date_tostring · date · nullableOptional
intervalstring · enumOptionalDefault: 1dPossible values:
entity_idstring · nullableOptional

Filter by entity ID

Responses
200

Successful Response

application/json
Other propertiesanyOptional
get/v1/{workspace_id}/analytics/surfaces/completion-rates
GET /v1/{workspace_id}/analytics/surfaces/completion-rates HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "ANY_ADDITIONAL_PROPERTY": "anything"
}

Get Surface Channel Effectiveness

Surface Channel Effectiveness

get

Per-channel completion rate and average time to complete.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Query parameters
daysinteger · min: 1 · max: 90OptionalDefault: 30
date_fromstring · date · nullableOptional
date_tostring · date · nullableOptional
Responses
200

Successful Response

application/json
Other propertiesanyOptional
get/v1/{workspace_id}/analytics/surfaces/channel-effectiveness
GET /v1/{workspace_id}/analytics/surfaces/channel-effectiveness HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "ANY_ADDITIONAL_PROPERTY": "anything"
}

Get Surface Field Abandonment

Surface Field Abandonment

get

Field-level drop-off analysis for abandoned surfaces.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
Query parameters
daysinteger · min: 1 · max: 90OptionalDefault: 30
date_fromstring · date · nullableOptional
date_tostring · date · nullableOptional
Responses
200

Successful Response

application/json
Other propertiesanyOptional
get/v1/{workspace_id}/analytics/surfaces/field-abandonment
GET /v1/{workspace_id}/analytics/surfaces/field-abandonment HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "ANY_ADDITIONAL_PROPERTY": "anything"
}

Get an Entity's Surface History

Entity Surface History

get

Per-entity surface history with preferred channel and completion stats.

Authorizations
AuthorizationstringRequired

API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.

Path parameters
workspace_idstring · uuidRequired
entity_idstring · uuidRequired
Query parameters
limitinteger · min: 1 · max: 100OptionalDefault: 20
Responses
200

Successful Response

application/json
Other propertiesanyOptional
get/v1/{workspace_id}/analytics/surfaces/entity/{entity_id}
GET /v1/{workspace_id}/analytics/surfaces/entity/{entity_id} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "ANY_ADDITIONAL_PROPERTY": "anything"
}

Entity Type

Surfaces introduce the interaction entity type to the world model ontology. Surface lifecycle events (created, delivered, opened, submitted) are tracked as first-class entities with full event sourcing.

Last updated

Was this helpful?