Developer Documentation

Connect to Florida's Private-Provider Registry

Build a read-only connection for a building department or connect a private provider firm's software to its own registration.

Transport
HTTPS
Protocol
2026-07-28
Session
Stateless

Overview

FLPPR exposes a Model Context Protocol (MCP) service over HTTPS. Building departments read registration data; private provider firms read and submit updates for their own registration. FLPPR does not expose a separate public REST API.

Development MCP URL
https://mcp.dev.flppr.app/mcp
Production MCP URL at launch
https://mcp.flppr.app/mcp
Development health check
GET https://mcp.dev.flppr.app/health

Get an API Key

Firm administrators create keys under Firm → Settings → API Keys. Building department administrators create keys under Department → Setup → API Keys. Each key is shown once as prefix/secret.

registry:read

Available to building departments and private provider firms. Department keys are read-only by design.

sync:write

Available only to private provider firms. Selecting it in the portal also grants registry:read.

Choose 90 days, 1 year, or no expiry. Rotate or revoke a key from the same page. Rotation revokes the old key and shows the new secret once.

Authenticate

Send your key in Authorization: Bearer <prefix>/<secret>. Every call to /mcp also needs the protocol, method, and content-type headers below. Add Mcp-Name for a tool call.

Required MCP request headers
HeaderValueWhen
MCP-Protocol-Version2026-07-28Every call
Mcp-MethodMust match the JSON-RPC body methodEvery call
Mcp-NameMust match params.nametools/call only
Content-Typeapplication/jsonEvery call

The service is stateless. Never send Mcp-Session-Id. You may send an optional x-request-id; otherwise FLPPR creates one.

Supported Mcp-Method values are tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read, resources/templates/list, and server/discover.

List available tools
curl https://mcp.dev.flppr.app/mcp \
  --request POST \
  --header 'Authorization: Bearer <prefix>/<secret>' \
  --header 'Content-Type: application/json' \
  --header 'MCP-Protocol-Version: 2026-07-28' \
  --header 'Mcp-Method: tools/list' \
  --data '{"jsonrpc":"2.0","id":"request-1","method":"tools/list","params":{}}'
Call search_firms
curl https://mcp.dev.flppr.app/mcp \
  --request POST \
  --header 'Authorization: Bearer <prefix>/<secret>' \
  --header 'Content-Type: application/json' \
  --header 'MCP-Protocol-Version: 2026-07-28' \
  --header 'Mcp-Method: tools/call' \
  --header 'Mcp-Name: search_firms' \
  --data '{"jsonrpc":"2.0","id":"request-2","method":"tools/call","params":{"name":"search_firms","arguments":{"query":"example","limit":25}}}'
JSON-RPC request and response
Request
{
  "jsonrpc": "2.0",
  "id": "request-1",
  "method": "tools/list",
  "params": {}
}

Response (abbreviated)
{
  "jsonrpc": "2.0",
  "id": "request-1",
  "result": {
    "tools": [
      { "name": "search_firms" }
    ]
  }
}

Connect an AI Assistant (MCP Quick-Start)

Any MCP-capable client can use these tools; the key decides what the client is allowed to do. Use the first block with clients that accept Claude Desktop or Cursor-style mcpServers configuration.

Claude Desktop or Cursor
{
  "mcpServers": {
    "flppr": {
      "url": "https://mcp.dev.flppr.app/mcp",
      "headers": {
        "Authorization": "Bearer <prefix>/<secret>"
      }
    }
  }
}
Generic MCP client
{
  "url": "https://mcp.dev.flppr.app/mcp",
  "headers": {
    "Authorization": "Bearer <prefix>/<secret>",
    "MCP-Protocol-Version": "2026-07-28"
  }
}

Read-only

Tools for Building Departments

A building department key has the registry:read scope. Access is limited at the storage layer to the department that owns the key.

search_firms

Search firm registrations available to the API key owner.

Input fields for search_firms
NameTypeRequiredLimits
querystringYes1–200 characters; *, ?, and % are rejected
countystringNoA department's county
cursorstringNoFrom nextCursor
limitintegerNo1–100; default 25

Output: { items: [{ id, name, registrationStatus, registrationVersion, updatedAt }], nextCursor? }

Access: Returns firms registered in the key owner's building department.

get_firm_registration

Get the registration projection for one firm and building department.

Input fields for get_firm_registration
NameTypeRequiredLimits
firmIdUUIDYes—
jurisdictionIdUUIDYes—

Output: { firmId, name, registrationStatus, registrationVersion, payloadVersion, rulesetVersion, updatedAt, professionals: [{ professionalId, rosterRole }] }

Access: The jurisdictionId must be the key owner's building department.

get_professional_qualifications

Get the published licenses for one professional.

Input fields for get_professional_qualifications
NameTypeRequiredLimits
professionalIdUUIDYes—
jurisdictionIdUUIDNo—

Output: { professionalId, licenses: CanonicalLicense[] }

Access: Available with a department read key.

get_jurisdiction_participation

Check a building department's participation status.

Input fields for get_jurisdiction_participation
NameTypeRequiredLimits
jurisdictionIdUUIDYes—

Output: { jurisdictionId, name, participationStatus, effectiveAt } where participationStatus is not_invited, invited, pending, active, withdrawal_pending, withdrawn, or terminated

Access: A department key may request only its own jurisdictionId.

verify_license

Return current canonical facts for a published license.

Input fields for verify_license
NameTypeRequiredLimits
sourceAuthorityenumYesdbpr, fbpe, or operator
boardstringYes—
licenseClassstringYes—
licenseNumberstringYes—

Output: CanonicalLicense

Access: Registry-wide, limited to licenses in a published firm registration.

get_registration_ledger

Read registration changes newest first, with cursor-based pagination.

Input fields for get_registration_ledger
NameTypeRequiredLimits
jurisdictionIdUUIDYes—
firmIdUUIDNo—
cursorstringNoFrom nextCursor
limitintegerNo1–100; default 25

Output: { items: [{ firmId, jurisdictionId, registrationStatus, payloadVersion, effectiveAt }], nextCursor? }

Access: Returns rows only for the key owner's building department.

CanonicalLicense

get_professional_qualifications and verify_license return the same canonical license shape.

CanonicalLicense
{
  id: UUID,
  sourceAuthority: "dbpr" | "fbpe" | "operator",
  board: string,
  licenseClass: string,
  licenseNumber: string,
  stateLabel: string,
  categories: string[] | null,
  status: string,
  issuedOn: "YYYY-MM-DD" | null,
  expiresOn: "YYYY-MM-DD" | null,
  verifiedAt: ISO datetime,
  freshness: "verified" | "stale" | "unknown",
  rulesetVersion: string
}

Tools for Private Provider Firms

A firm's read key uses registry:read. The six read tools use the inputs and outputs documented above, with access narrowed as follows.

Firm access rules for read tools
ToolFirm access
search_firmsReturns only the key owner's firm.
get_firm_registrationThe firmId must be the key owner's firm.
get_professional_qualificationsAvailable with a firm read key.
get_jurisdiction_participationA firm key may request any building department.
verify_licenseRegistry-wide, limited to licenses in a published firm registration.
get_registration_ledgerReturns only the key owner's firm rows.

Firm-only writes

Submit Firm Changes

Write tools use sync:writeand can affect only the key owner's firm. They submit proposed changes; a firm administrator completes them in the portal. Signatures are always human.

Reuse an idempotency key with the same payload to receive the original result with replayed: true. Reusing it with different content returns an idempotency-key payload mismatch.

sync_roster

Submit roster intent and request license matching.

Input fields for sync_roster
NameTypeRequiredLimits
idempotencyKeystringYes16–200 characters
rosterarrayYesUp to 500 entries
roster[].professionalExternalIdstringYes—
roster[].licenseReferencesarrayYes1–32 references
roster[].activebooleanYes—

Output: { accepted, rejected, stagedVersion, matchRequested, replayed }

Completion: The submission captures intent and creates matching requests when needed. A firm administrator completes the change in the portal.

sync_engagements

Add one pending-signature roster entry and return the portal signing URL.

Input fields for sync_engagements
NameTypeRequiredLimits
idempotencyKeystringYes16–200 characters
engagementsarrayYesExactly one entry
engagements[].firmExternalIdstringYes—
engagements[].professionalExternalIdstringYes—
engagements[].licenseReferencesarrayYes—
engagements[].rosterRoleenumYesqualifier or dar
engagements[].relationshipTypeenumYesemployee, agent, officer, or partner
engagements[].performsInspectionsbooleanYes—
engagements[].employeeBenefitsAttestedbooleanYes—
engagements[].supervisorProfessionalExternalIdstringNoRequired for provisional-only professionals
engagements[].hvwzExperienceYearsintegerNo0–100
engagements[].effectiveOndateYesYYYY-MM-DD

Output: { accepted, rejected, stagedVersion, engagementId, engagementStatus: "pending_signature", requiresSignature, signingUrl, replayed }

Completion: The person signs in the portal. An inspection role requires dar, employee, and an attested employee-benefits relationship. A provisional-only professional needs a BCA supervisor.

sync_insurance

Submit policy facts against a certificate object that FLPPR has already scanned.

Input fields for sync_insurance
NameTypeRequiredLimits
idempotencyKeystringYes16–200 characters
policiesarrayYesUp to 100 entries
policies[].externalIdstringYes—
policies[].insurerstringYes—
policies[].insurerFloridaAuthorizedbooleanYes—
policies[].amBestRatingstringNo—
policies[].policyNumberstringYes—
policies[].coverageFormenumYesoccurrence or claims_made
policies[].occurrenceLimitCentsintegerYes—
policies[].aggregateLimitCentsintegerYes—
policies[].effectiveOndateYesYYYY-MM-DD
policies[].cancellationOndateNoYYYY-MM-DD
policies[].coveredPartiesstring[]Yes—
scannedObject.tokenstringYesIssued by FLPPR support
scannedObject.objectVersionstringYesIssued by FLPPR support

Output: { accepted, rejected, stagedVersion, replayed }

Completion: This tool requires a scanned certificate token issued by FLPPR support today. It is not self-serve.

Profile changes, certificate upload, signing, roster-entry termination, and key management stay in the portal.

Keeping in Sync

Poll get_registration_ledger. It returns newest changes first and provides a cursor for the next page. Refresh get_firm_registration for each changed firm.

Webhooks: Coming

Subscription Events

Today these events reach users by email and in the portal's notification feed. Webhook delivery is not available yet.

Live Events

  • firm_registered
  • firm_lapsed
  • firm_reactivated
  • roster_changed
  • coi_expiring
  • coi_expired
  • registration_ended
  • jurisdiction_withdrawal_pending
  • jurisdiction_withdrawn
  • jurisdiction_terminated
  • firm_closed

Reserved Events

  • license_status_changed
  • new_participating_firm

coi_expiring includes policy_id and expires_on.

Limits and Errors

Rate Limit

120 requests per minute, per key, per tool, measured by fixed calendar minute.

Request Size

Request bodies may be up to 256 KiB. Larger requests return HTTP 413.

HTTP 429 returns Retry-After seconds and a response body with error and auditId.

Transport Errors

HTTP transport errors
StatusMeaning
401Unauthorized
403Origin or host not allowed, or scope forbidden
404Not found
405Method not allowed
413Payload too large
415Unsupported media type
429Rate limited
500 / 503Request failed

JSON-RPC Errors

JSON-RPC errors
CodeMeaning
-32700Parse error
-32600Invalid request
-32601Method not found
-32020Header mismatch
-32022Unsupported protocol version

Tool-Level Errors

Tool error shape
{
  "isError": true,
  "content": [{ "type": "text", "text": "..." }],
  "structuredContent": {
    "error": "...",
    "httpStatus": 400,
    "auditId": "flppr_aud_..."
  }
}

Every response includes x-request-idand an auditId. Include both when you contact [email protected]. Authentication failures return HTTP 401 with only { "error": "Unauthorized" }.

Data We Hold and Where It Comes From

The MCP service returns the same registration and state licensing data available in the FLPPR portal—nothing more. See About the Data for the official sources and sync details.

Support

Email [email protected] or choose Need help? in the app. Include the x-request-id and auditId for the failed request.