Surfaces
Agent-generated data collection interfaces: SurfaceSpec, fields, channels, lifecycle, and submission handling.
Surfaces are agent-generated data collection interfaces delivered to patients through existing communication channels. Agents analyze entity state and data gaps in the world model, generate a SurfaceSpec, and the platform renders and delivers it. Submissions flow back as world model events through standard confidence gates and review.
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:
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:
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
/v1/{ws}/surfaces
POST
Create a surface. Returns spec + signed token + absolute url.
/v1/{ws}/surfaces
GET
List surfaces. Filterable by entity_id, status. Paginated.
/v1/{ws}/surfaces/{id}
GET
Get a specific surface with current status.
/v1/{ws}/surfaces/{id}
PATCH
Update a surface spec.
/v1/{ws}/surfaces/{id}
DELETE
Archive (soft-delete) a surface.
/v1/{ws}/surfaces/review
GET
List surfaces pending review.
/v1/{ws}/surfaces/{id}/approve
POST
Approve a surface pending review.
/v1/{ws}/surfaces/{id}/reject
POST
Reject a surface pending review.
/v1/{ws}/surfaces/{id}/reshape
POST
Create a new surface containing only the unfilled fields.
/v1/{ws}/surfaces/{id}/progress
GET
Get field-level completion status.
/v1/{ws}/surfaces/{id}/deliver
POST
Deliver via email (or record a web handoff). Sends the surface URL to channel_address, records a lifecycle event. SMS/phone-number delivery is not supported and returns 422.
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.
The response includes delivery metadata:
surface_id
string
The surface that was delivered
status
string
Updated status. Literal of delivered or pending_review.
channel
string
The delivery channel used
channel_address
string
The delivery target (email)
url
string
The full surface URL
message_id
string
Provider message ID for tracking
from_number
string
The number the message was sent from
from_address
string
The address the email was sent from
delivery_provider
string
The delivery provider used
delivered_at
string
ISO 8601 timestamp of delivery
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
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.
Field Types
Short text
text
Name, address, pharmacy
Long text
textarea
Symptoms, special instructions
Date
date
Date of birth, appointment date
Phone
phone
Contact number, emergency contact
email
Patient email for follow-up
Number
number
Age, weight, dosage
Single select
select
Preferred provider, insurance type
Multi select
multiselect
Symptom checklist, available days
Checkbox
checkbox
Consent confirmation, HIPAA acknowledgment
Photo
photo
Insurance card, wound photo, ID
Signature
signature
Digital consent, authorization
File
file
Referral letter, lab results, prior records
Heading
heading
Section headers within longer forms (display only)
Info
info
Read-only explanatory text between fields (display only)
SurfaceSpec
The specification an agent generates to define a data collection surface.
entity_id
UUID
Yes
-
Entity this surface is for
title
string
Yes
-
Surface title shown to patient
description
string
No
-
Explanatory text below the title
fields
SurfaceField[]
Yes
-
1-200 data collection fields
channel
ChannelType
No
web
Delivery channel
expires_in_hours
integer
No
168 (7 days)
TTL in hours (range: 1-8760)
context
object
No
{}
Agent-provided context metadata
resource_type
string
No
-
Optional resource type tag (max 128 chars)
branding
BrandingConfig
No
-
Custom branding overrides (falls back to workspace branding)
sections
SurfaceSection[]
No
-
Multi-page form sections (each groups fields into a step)
submit_button_text
string
No
-
Custom label for the submit button (max 128 chars)
completion_title
string
No
-
Title shown after submission (max 256 chars)
completion_message
string
No
-
Message shown after submission (max 2000 chars)
completion_action_url
string
No
-
Optional link shown on the completion screen (max 2048 chars)
SurfaceField
A single data collection field within a surface.
key
string
Yes
-
Unique field identifier (1-128 chars)
label
string
Yes
-
Display label shown to patient
field_type
FieldType
Yes
-
One of the 14 field types above
required
boolean
No
true
Whether the field must be filled
options
string[]
No
-
Choices for select, multiselect fields
description
string
No
-
Help text below the field
placeholder
string
No
-
Placeholder text (max 256 chars)
prefill_value
any
No
-
Pre-populated value from known data
validation
object
No
-
Field-specific validation rules
sensitive
boolean
No
false
PHI flag for additional handling
condition
object
No
-
Conditional display rules (show/hide based on other fields)
consent_text
string
No
-
Consent language displayed with the field (max 5000 chars)
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).
logo_url
string
No
Logo image URL (max 2048 chars)
primary_color
string
No
Primary brand color, e.g., #1A73E8 (max 32 chars)
background_color
string
No
Page background color (max 32 chars)
font_family
string
No
Font family name (max 256 chars)
Workspace-level branding is configured through the branding settings endpoints:
/v1/{ws}/settings/branding
GET
Get workspace default branding (any role)
/v1/{ws}/settings/branding
PUT
Update workspace default branding (admin/owner)
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.
SurfaceSection
Groups fields into pages for multi-step forms. When sections are defined, the patient sees one section at a time with navigation between steps.
title
string
Yes
Section heading shown to patient
description
string
No
Explanatory text for the section
field_keys
string[]
Yes
1-100 field keys from the surface's fields array to include in this section
condition
object
No
Conditional display rules for the whole section
SurfaceSubmission
Data submitted by a patient when completing a surface.
surface_id
UUID
Which surface was submitted
entity_id
UUID
Entity the surface belongs to
data
object
Submitted field values (keyed by field key)
submitted_at
ISO timestamp
When the submission occurred
channel
ChannelType
Channel the submission came through
fields_submitted
string[]
List of field keys that were filled
partial
boolean
Whether this is a partial (auto-save) submission
Lifecycle
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: All surface events (creation, delivery, submission) are linked to the
entity_idon the event row, so they appear in entity timeline queries and trigger state recomputation
When a patient submits a surface, entity state recomputation runs within the same transaction. Submitted form data flows directly into entity demographic and clinical projections with no delay.
Surface data flows through the same confidence gates, review queues, and entity resolution pipelines as data from any other source. No special handling is required.
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.
GET /s/f/{surface_id}
None
Short URL redirect. Generates a fresh HMAC token and issues a 302 redirect to /s/{token}. Used in email delivery for compact links. Returns 404 if not found, 410 if expired.
GET /s/{token}
Token (no API key)
Render surface as mobile-first HTML. Updates status to opened.
POST /s/{token}/submit
Token (no API key)
Accept form submission. Writes events at confidence 0.5. Rejects if already completed or expired. Triggers entity state recomputation within the same transaction.
PUT /s/{token}/fields/{key}
Token (no API key)
Incremental auto-save for a single field. Updates status 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.
Atomic lifecycle: status transitions (opened, partial, completed) are written atomically. Check and insert happen in a single transaction to prevent race conditions like double submissions.
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
The gap scanner is a background loop on the connector runner that proactively detects missing entity data and creates surfaces. Configuration is per-workspace via settings endpoints.
GET /settings/gap-scanner. Get current gap scanner settings (any role).
PUT /settings/gap-scanner. Update gap scanner settings (admin/owner). Partial updates supported.
POST /settings/gap-scanner/preview. Preview gap detection (dry run) without creating surfaces.
POST /settings/gap-scanner/scan. Trigger one scan tick on demand.
enabled
boolean
false
Enable/disable the scanner
scan_interval_seconds
integer
300 (5 min)
How often to scan
appointment_lookahead_hours
integer
72 (3 days)
How far ahead to check for upcoming appointments
cooldown_hours
integer
168 (7 days)
How long before re-scanning the same entity
max_surfaces_per_tick
integer
10
Maximum surfaces created per scan cycle
max_pending_surfaces
integer
3
Skip entities with this many unfinished surfaces (fatigue gating)
min_completion_rate
float (0-1)
0.0
Skip entities whose completion rate is below this threshold
channel_optimization
boolean
false
When enabled, use each entity's historically preferred channel instead of the requirement's default
requirements
GapRequirement[]
[]
Gap detection rules
GapRequirement
name
string
Yes
-
Rule name
entity_type
string
No
person
Entity type to scan
trigger
string
No
upcoming_appointment
When to check: upcoming_appointment or recent_interaction
required_fields
GapRequiredField[]
Yes
-
1-50 fields that must be present
channel
ChannelType
No
email
Delivery channel for generated surfaces (sms is not a deliverable channel)
priority
string
No
normal
low, normal, or high
surface_title
string
No
Rule name
Title for generated surfaces
surface_description
string
No
-
Description shown on generated surfaces
GapRequiredField
path
string
Yes
Dot-notation path into entity state (e.g., insurance.carrier)
label
string
Yes
Display label for the surface field
field_type
FieldType
No
Field type (default: text)
min_items
integer
No
For list fields, minimum items required
The scanner reports through the connector runner's metrics. Changes to settings are audit-logged.
Surface Analytics
Four endpoints under /v1/{workspace_id}/analytics/surfaces/ for closed-loop optimization:
GET /analytics/surfaces/completion-rates
Overall completion rate, time-bucketed trend, by-source breakdown (agent, gap scanner, manual). Filterable by entity_id.
GET /analytics/surfaces/channel-effectiveness
Per-channel completion rate and average time-to-complete
GET /analytics/surfaces/field-abandonment
Per-field drop-off rate and save rate for abandoned surfaces
GET /analytics/surfaces/entity/{entity_id}
Per-entity surface history: completion stats, preferred channel, recent surfaces
Common parameters (completion-rates, channel-effectiveness, field-abandonment):
days
integer (1-90)
30
Lookback window
date_from / date_to
date
-
Explicit date range
interval
1h / 1d / 1w
1d
Time bucket for trend data (completion-rates only)
Entity history accepts limit (1-100, default 20).
All endpoints require viewer+ permissions and are workspace-scoped.
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.
API Reference
Last updated
Was this helpful?

