Skip to main content

Policies

A policy (also called an “access recipe”) is a set of rules that governs who can retrieve which artifacts from a dock. Policies are composable, versioned, and support staged rollout.

Recipe Structure

A policy recipe defines:
  • Who — Which recipients or recipient groups are authorized
  • What — Which artifacts (by type, metadata, or explicit IDs) are accessible
  • How — What authentication factors are required
  • When — Optional time-based constraints (effective dates, expiration)

Persona-Based Recipes

Each stakeholder type has distinct access requirements. Here are the four standard recipe patterns:

Mortgagee — Bulk API Access

{
  "name": "Mortgagee Bulk Access",
  "stakeholderClass": "mortgagee",
  "artifactTypes": ["declaration-page", "certificate-of-insurance", "endorsement"],
  "auth": {
    "factors": ["shared_passphrase", "tls_certificate"],
    "tls": { "require_mutual": true, "min_version": "1.2" }
  },
  "access": {
    "method": "bulk_api",
    "max_batch_size": 10000
  },
  "match": {
    "identifiers": ["lender_id", "policy_number"]
  }
}
Mortgagees authenticate with a shared passphrase (generated via the Secrets API) and a mutual TLS certificate. They access documents through the bulk retrieval API, pulling thousands of dec pages per job.

Agent — Portal + Bulk Download

{
  "name": "Agent Portal Access",
  "stakeholderClass": "agent",
  "artifactTypes": ["declaration-page", "policy-packet", "endorsement", "renewal-notice"],
  "auth": {
    "factors": ["webauthn"],
    "webauthn": { "challenge_type": "platform_or_cross_platform" }
  },
  "access": {
    "method": ["portal", "bulk_download"]
  },
  "match": {
    "identifiers": ["agency_code", "policy_number"]
  }
}
Insurance agents authenticate with a WebAuthn challenge — a FIDO2 security key or device biometric. They access documents through the branded portal for single lookups, or bulk download for client batch operations.

Policyholder — Single Retrieval

{
  "name": "Policyholder Self-Service",
  "stakeholderClass": "policyholder",
  "artifactTypes": ["declaration-page", "id-card", "renewal-notice"],
  "auth": {
    "factors": ["sms_otp"],
    "otp": { "delivery": "sms", "code_length": 6, "ttl_seconds": 300 }
  },
  "access": {
    "method": "portal",
    "max_concurrent_downloads": 1
  },
  "match": {
    "identifiers": ["email", "date_of_birth", "policy_number"]
  }
}
Policyholders verify their identity with email/phone + date of birth, then receive a 6-digit SMS OTP to authorize retrieval. Access is limited to their own documents via the self-service portal.

Auditor — Time-Boxed Read-Only

{
  "name": "External Audit Access",
  "stakeholderClass": "auditor",
  "artifactTypes": ["*"],
  "auth": {
    "factors": ["badge_id", "nda_hash"],
    "nda": { "hash_algorithm": "sha256", "require_match": true }
  },
  "access": {
    "method": "portal",
    "read_only": true,
    "download_enabled": false
  },
  "match": {
    "identifiers": ["badge_id", "nda_hash"]
  },
  "constraints": {
    "time_window": {
      "start": "2025-01-15T00:00:00Z",
      "end": "2025-02-15T00:00:00Z"
    },
    "auto_expire": true
  }
}
Auditors authenticate with a badge ID and the SHA-256 hash of their signed NDA. Access is read-only, non-downloadable, and automatically expires when the time window closes — no manual revocation needed.

How match.identifiers Works

The match.identifiers array in a recipe defines the identifiers required for access — it does not require them to be stored on the recipient record at registration time. At access time, the policy engine resolves identifiers from two sources:
  1. Stored identifiers — values saved on the recipient record (via the Create Recipient or Update Recipient endpoints)
  2. Submitted identifiers — values the recipient provides at access time through the portal or API
The engine merges both sources and evaluates the recipe. If all required identifiers are present and valid, access is granted. If any are missing, access is denied.
ScenarioStoredSubmittedResult
Mortgagee with pre-populated lender_id + policy_numberBoth presentAccess granted
Policyholder with no stored identifiersSubmits date_of_birth + policy_numberAccess granted
Policyholder with stored phone, submits date_of_birthphonedate_of_birth, policy_numberAccess granted (merged)
Agent missing agency_codepolicy_number onlyAccess denied
Pre-populating identifiers is not required — the identifiers field on a recipient is optional. What matters is that all identifiers listed in match.identifiers are available (from either source) at the time of access.

Lifecycle

Policies progress through three stages:
DRAFT → PILOT → PRODUCTION
StageBehavior
DraftNot enforced. Safe to edit and iterate.
PilotEnforced for a subset of recipients. Use for testing before global rollout.
ProductionFully enforced for all matched recipients.

Version Control

Every change to a policy creates a new immutable version. You can:
  • List versions — See the full history of a policy
  • Compare versions — Understand what changed between iterations
  • Rollback — Revert to any previous version instantly
Version rollback creates a new version with the old recipe — it does not delete intermediate versions. The full history is always preserved for audit purposes.

Simulation

Before publishing a policy change, run a simulation to preview its impact:
  • How many recipients gain or lose access
  • Which authentication factors are missing per recipient
  • Which recipients are non-compliant with the new rules
  • Recommendations for transition (e.g., “16 mortgagees lack TLS certificates — consider a grace period”)

Templates

Docyard provides pre-built policy templates for each persona:
TemplatePersonaKey Factors
mortgagee-bulk-apiMortgageePassphrase + mTLS, bulk API
agent-portal-accessAgentWebAuthn, portal + bulk download
policyholder-self-servicePolicyholderSMS OTP, single retrieval
auditor-time-boxedAuditorBadge ID + NDA hash, auto-expiring
Create a policy from a template and customize it for your dock.