Skip to main content

Migration Guide

Move from our legacy API (api.thirdfort.io) to our new API (api.thirdfort.com).

Note: This migration guide covers the most common use cases. For questions or support, contact api@thirdfort.com.


Overview

This guide helps you migrate from the Thirdfort Legacy API (api.thirdfort.io) to the new Thirdfort Client API (api.thirdfort.com).

Why Migrate?

  • Access new products and features as they become available on the new platform
  • Improved API design with consistent resource-oriented patterns
  • Better developer experience with modern authentication and clearer documentation

Support Timeline

  • Legacy API: Will be supported for the foreseeable future
  • New API: Recommended for all new integrations
  • Migration Support: Contact api@thirdfort.com for assistance

Key Differences at a Glance

AspectLegacy APINew API
Base URLhttps://api-v2.thirdfort.iohttps://api.thirdfort.com/client/api
AuthenticationJWT with RSA signaturesOAuth 2.0 client credentials
Primary Resourcetransactionschecks
Organizationtenantsorganizations
API StyleRESTREST
Field Namingsnake_casecamelCase
Date FormatISO 8601 stringsStructured objects

1. Authentication Migration

Legacy API: JWT with RSA Signatures

# Generate JWT token with RSA private key
# (Complex multi-step process with token generation and signing)

New API: OAuth 2.0 Client Credentials

# Simple OAuth 2.0 token request
curl -X POST "https://creative-jungle-73-staging.authkit.app/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"

Response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}

Using the token:

curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
https://api.thirdfort.dev/client/api/v1/...

Migration Steps

  1. Obtain OAuth 2.0 credentials from Thirdfort (contact api@thirdfort.com)
  2. Update your token acquisition logic to use OAuth 2.0 client credentials flow
  3. Store credentials securely (Client ID and Secret)
  4. Implement token refresh (tokens expire after 1 hour)
  5. Remove JWT generation code (no longer needed)

2. Base URL Migration

Legacy API

  • Production: https://api-v2.thirdfort.io
  • Sandbox: https://sandbox.api.thirdfort.io

New API

  • Production: https://api.thirdfort.com/client/api/v1
  • Nonproduction: https://api.thirdfort.dev/client/api/v1

Migration Steps

  1. Update all API endpoint URLs to use new base URL
  2. Add /client/api/v1 prefix to all endpoints
  3. Test in nonproduction environment first

3. Resource Name Migration

Transactions → Checks

The primary resource has been renamed from transactions to checks.

Legacy APINew API
POST /v2/transactionsPOST /v1/{parent}/checks
GET /v2/transactions/{id}GET /v1/{check_name}
GET /v2/transactions/{id}/_summaryGET /v1/{check_name}/checkSummary
GET /v2/transactions/{id}/reportsGET /v1/{check_name}/findings

Tenants → Organizations

Legacy APINew API
tenantsorganizations
tenant_idOrganization ID (part of resource name)

4. Creating Checks (Identity Verification)

This is the most common use case: creating an identity verification check.

Legacy API: Create Transaction

New API: Create Check

POST /v1/organizations/{org_id}/teams/{team_id}/checks
{
"displayName": "Identity verification for Jane Smith",
"clientReference": "Thirdfort-Case0123",
"template": "checkTemplates/identity-verification-check-v1-0-0",
"params": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckParams",
"subject": {
"givenName": "Jane",
"familyName": "Smith",
"email": "jane.smith@example.com",
"phoneNumber": "+447700112233"
},
"enableOngoingMonitoring": true
}
}

Key Changes

  1. Endpoint includes parent: /organizations/{org_id}/teams/{team_id}/checks
  2. Required fields renamed:
    • namedisplayName
    • refclientReference
  3. Template-based: Use template field to specify check type
  4. Structured params: Use params object with @type field
  5. camelCase fields: givenName, familyName, phoneNumber (not snake_case)
  6. Simplified options: enableOngoingMonitoring: true (not opts.monitored)

Task Mapping

Legacy TaskNew API Equivalent
report:identity + report:footprint + report:pepstemplate: "checkTemplates/identity-verification-check-v1-0-0"
report:screening:litetemplate: "checkTemplates/clientonly-verification-check-v1-0-0"
report:sof-v1template: "checkTemplates/source-of-funds-check-v1-0-0"
documents:poaIncluded in identity verification

5. Retrieving Check Results

Legacy API: Get Transaction Summary

GET /v2/transactions/{transaction_id}/_summary

Response:

{
"transaction": {
"id": "348302372",
"status": "closed",
"name": "Purchase of 14A Mansion House"
},
"reports": [
{
"type": "identity",
"status": "closed",
"result": "clear"
},
{
"type": "peps",
"status": "closed",
"result": "consider"
}
]
}

New API: Get Check Summary

GET /v1/organizations/{org_id}/teams/{team_id}/checks/{check_id}/checkSummary

Response:

{
"name": "organizations/.../teams/.../checks/.../checkSummary",
"createTime": "2026-03-06T14:07:00.537001Z",
"payload": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckSummary",
"overallRecommendation": {
"recommendation": "CONSIDER",
"description": "One or more items require consideration"
},
"identityDocumentCheckResult": { ... },
"livenessCheckResult": { ... },
"screeningCheckResult": { ... }
},
"reportUrl": "https://files.thirdfort.dev/client/downloads/objects/...",
"summaryReportUrl": "https://files.thirdfort.dev/client/downloads/objects/..."
}

Key Changes

  1. Endpoint path: /{check_id}/checkSummary (not /_summary)
  2. Structured payload: Results in payload object with @type
  3. Recommendation values: CLEAR, CONSIDER, FAIL (uppercase)
  4. PDF URLs: Top-level reportUrl and summaryReportUrl fields
  5. Check-specific results: Different payload structure per check type

6. Downloading PDF Reports

Legacy API: Download Reports

# Get report URL from transaction summary
GET /v2/transactions/{transaction_id}/reports/{report_id}

# Download PDF (URL from report response)
GET {pdf_url}

New API: Download Reports

# Get PDF URLs from check summary
GET /v1/organizations/{org_id}/teams/{team_id}/checks/{check_id}/checkSummary

# Download full PDF report
curl -X GET "https://files.thirdfort.dev/client/downloads/objects/{object_id}" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-o report.pdf

# Download summary PDF report
curl -X GET "https://files.thirdfort.dev/client/downloads/objects/{object_id}" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-o summary.pdf

Key Changes

  1. PDF URLs in summary: Available directly in checkSummary response
  2. Two PDF types: reportUrl (full) and summaryReportUrl (summary)
  3. Authentication required: Must include Authorization header
  4. URL format: /downloads/objects/{uuid} (not /downloads/{id})

7. Field Name Mapping

Common Field Changes

Legacy APINew API
transactioncheck
transaction_idcheck_id
tenant_idOrganization ID (in resource name)
actor.namesubject.givenName + subject.familyName
actor.phonesubject.phoneNumber
actor.emailsubject.email
taskstemplate + params
statusstate
resultrecommendation
created_atcreateTime
updated_atupdateTime

Status/State Mapping

Legacy StatusNew State
openACTIVE
closedINACTIVE
abortedCANCELLED
N/ADELETED

Result/Recommendation Mapping

Legacy ResultNew Recommendation
clearCLEAR
considerCONSIDER
failFAIL

8. Date Format Migration

Legacy API: ISO 8601 Strings

{
"created_at": "2024-01-15T10:00:00Z",
"dob": "1990-06-15"
}

New API: Structured Objects

{
"createTime": "2024-01-15T10:00:00Z",
"dateOfBirth": {
"year": 1990,
"month": 6,
"day": 15
}
}

Migration Steps

  1. Timestamps remain strings: createTime, updateTime use ISO 8601
  2. Dates of birth: Convert to structured object with year, month, day
  3. Update parsing logic: Handle structured date objects

9. Client-Only Verification (Lite Screening)

This is a common use case for quick screening without consumer interaction.

Legacy API: Lite Screening

POST /v2/transactions
{
"type": "v2",
"name": "Lite screening for John Doe",
"ref": "screening-123",
"request": {
"tasks": [
{ "type": "report:screening:lite", "opts": { "monitored": true } }
],
"expectations": {
"name:lite": {
"first_name": "John",
"last_name": "Doe"
},
"dob": {
"year": 1985,
"month": 6,
"day": 15
},
"address": {
"address_1": "123 High Street",
"address_2": "London",
"postcode": "SW1A 1AA",
"country": "GB"
}
}
}
}

Note: Legacy API requires actor to be omitted for lite screening.

New API: Client-Only Verification

POST /v1/organizations/{org_id}/teams/{team_id}/checks
{
"displayName": "Client-only verification for John Doe",
"clientReference": "screening-123",
"template": "checkTemplates/clientonly-verification-check-v1-0-0",
"params": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.ClientOnlyVerificationCheckParams",
"subject": {
"givenName": "John",
"familyName": "Doe",
"dateOfBirth": {
"year": 1985,
"month": 6,
"day": 15
}
},
"address": {
"buildingNumber": "123",
"street": "High Street",
"locality": "London",
"postalCode": "SW1A 1AA",
"countryCode": "GBR"
},
"enableOngoingMonitoring": true
}
}

Key Changes

  1. No actor vs expectations: New API uses subject for all data
  2. Structured address: Uses buildingNumber, street, locality, postalCode, countryCode
  3. Country code format: GBR (ISO 3166-1 alpha-3) not GB (alpha-2)
  4. Simplified: No need to omit fields or use expectations object

10. Notifications Migration

The notification system has changed significantly between the legacy and new APIs.

Key Changes

AspectLegacy APINew API
ScopePer-transactionOrganization-level
PollingInbox-based with acknowledgmentCursor-based pagination
WebhooksPer-transaction configurationOrganization-level (managed by Thirdfort)
HMAC KeyIntegrator-providedThirdfort-managed
Signature HeaderX-Signature (hexadecimal)x-thirdfort-signature (base64)

Polling Migration

Legacy (v2): Inbox-based system

  • Create inbox: POST /v2/inboxes
  • Configure per-transaction: metadata.notify.type = "inbox"
  • Poll for messages: GET /v2/inboxes/{id}/messages
  • Acknowledge messages: PATCH /v2/inboxes/{id}/messages/{msgId}

New: Cursor-based pagination

  • No inbox creation needed
  • Organization-level notifications: GET /v1/organizations/{org}/notifications
  • Use page_token for pagination (no acknowledgment)
  • Implement deduplication using notification IDs

Migration Steps:

  1. Remove inbox creation logic
  2. Remove per-check notification configuration
  3. Implement cursor-based polling with nextPageToken
  4. Replace acknowledgment with deduplication (store processed notification IDs)
  5. Update notification handling for new payload structure

See the Polling for Notifications guide for complete implementation details.

Webhook Migration

Legacy: Per-transaction webhooks

  • Configured per-check in metadata.notify
  • Integrator-provided HMAC key
  • Signature in X-Signature header (hexadecimal)

New: Organization-level webhooks

  • Configured by Thirdfort at organization level
  • Thirdfort-managed HMAC secret
  • Signature in x-thirdfort-signature header (base64)

Migration Steps:

  1. Contact api-support@thirdfort.com to configure webhooks
  2. Remove per-check webhook configuration from requests
  3. Update webhook endpoint to handle organization-level notifications
  4. Update signature verification:
    • Change header from X-Signature to x-thirdfort-signature
    • Change format from hexadecimal to base64
    • Use Thirdfort-provided secret
  5. Implement idempotency using notification IDs
  6. Test in nonproduction environment

Notification Types

The new API provides structured notification types:

  • notification.client.check_complete.v1 - Check completed
  • notification.client.report_generated.v1 - Report generated
  • notification.client.ongoing_monitoring_hit.v1 - Monitoring hit detected
  • notification.client.ongoing_monitoring_started.v1 - Monitoring started
  • notification.client.ongoing_monitoring_renewed.v1 - Monitoring renewed

Choosing Between Polling and Webhooks

Use Polling when:

  • You cannot expose a public webhook endpoint
  • You prefer simpler infrastructure
  • You have moderate notification volume
  • Slight delays (30-60 seconds) are acceptable

Use Webhooks when:

  • You need real-time notifications (sub-second delivery)
  • You have high notification volume
  • You want to minimize API calls
  • You can maintain a public HTTPS endpoint

11. Common Migration Issues

Issue: 400 Bad Request - "field required"

Cause: Missing required fields (displayName, clientReference, @type)

Solution: Ensure all required fields are included in request

Issue: 404 Not Found

Cause: Incorrect endpoint URL or resource name format

Solution:

  • Verify endpoint includes parent: /v1/{parent}/checks
  • Check resource name format: organizations/{org_id}/teams/{team_id}/checks/{check_id}

Issue: 401 Unauthorized

Cause: Invalid or expired OAuth token

Solution:

  • Verify OAuth 2.0 credentials are correct
  • Implement token refresh (tokens expire after 1 hour)
  • Check Authorization: Bearer {token} header is included

Issue: PDF Download Fails

Cause: Missing authentication or incorrect URL format

Solution:

  • Include Authorization header in PDF download requests
  • Use complete URL from reportUrl field
  • Verify URL includes /objects/ path segment

Issue: Date Parsing Errors

Cause: Using string dates instead of structured objects

Solution:

  • Convert date strings to structured objects: {year, month, day}
  • Update date parsing logic in your code

12. Support and Resources

Documentation

  • Quickstart Guide: See quickstart.md for step-by-step guide
  • Product Guides: See products/ directory for detailed product documentation
  • API Reference: Contact api@thirdfort.com for full API reference

Support

Getting Credentials

  • OAuth 2.0 Credentials: Contact api@thirdfort.com
  • Nonproduction Access: Request via email

13. FAQ

Q: When will the legacy API be deprecated? A: The legacy API will be supported for the foreseeable future. There is no planned deprecation date at this time.

Q: Can I use both APIs simultaneously? A: Yes, you can run both integrations in parallel during migration.

Q: Will my existing transactions be migrated? A: No, existing transactions remain in the legacy system. New checks are created in the new system.

Q: Do I need new credentials? A: Yes, you need OAuth 2.0 credentials (Client ID and Secret) for the new API.

Q: What if I encounter issues during migration? A: Contact api@thirdfort.com for support.


Last updated: 2026-03-06 For questions or support, contact api@thirdfort.com