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
| Aspect | Legacy API | New API |
|---|---|---|
| Base URL | https://api-v2.thirdfort.io | https://api.thirdfort.com/client/api |
| Authentication | JWT with RSA signatures | OAuth 2.0 client credentials |
| Primary Resource | transactions | checks |
| Organization | tenants | organizations |
| API Style | REST | REST |
| Field Naming | snake_case | camelCase |
| Date Format | ISO 8601 strings | Structured 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
- Obtain OAuth 2.0 credentials from Thirdfort (contact api@thirdfort.com)
- Update your token acquisition logic to use OAuth 2.0 client credentials flow
- Store credentials securely (Client ID and Secret)
- Implement token refresh (tokens expire after 1 hour)
- 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
- Update all API endpoint URLs to use new base URL
- Add
/client/api/v1prefix to all endpoints - Test in nonproduction environment first
3. Resource Name Migration
Transactions → Checks
The primary resource has been renamed from transactions to checks.
| Legacy API | New API |
|---|---|
POST /v2/transactions | POST /v1/{parent}/checks |
GET /v2/transactions/{id} | GET /v1/{check_name} |
GET /v2/transactions/{id}/_summary | GET /v1/{check_name}/checkSummary |
GET /v2/transactions/{id}/reports | GET /v1/{check_name}/findings |
Tenants → Organizations
| Legacy API | New API |
|---|---|
tenants | organizations |
tenant_id | Organization 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
- Endpoint includes parent:
/organizations/{org_id}/teams/{team_id}/checks - Required fields renamed:
name→displayNameref→clientReference
- Template-based: Use
templatefield to specify check type - Structured params: Use
paramsobject with@typefield - camelCase fields:
givenName,familyName,phoneNumber(not snake_case) - Simplified options:
enableOngoingMonitoring: true(notopts.monitored)
Task Mapping
| Legacy Task | New API Equivalent |
|---|---|
report:identity + report:footprint + report:peps | template: "checkTemplates/identity-verification-check-v1-0-0" |
report:screening:lite | template: "checkTemplates/clientonly-verification-check-v1-0-0" |
report:sof-v1 | template: "checkTemplates/source-of-funds-check-v1-0-0" |
documents:poa | Included 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
- Endpoint path:
/{check_id}/checkSummary(not/_summary) - Structured payload: Results in
payloadobject with@type - Recommendation values:
CLEAR,CONSIDER,FAIL(uppercase) - PDF URLs: Top-level
reportUrlandsummaryReportUrlfields - 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
- PDF URLs in summary: Available directly in
checkSummaryresponse - Two PDF types:
reportUrl(full) andsummaryReportUrl(summary) - Authentication required: Must include
Authorizationheader - URL format:
/downloads/objects/{uuid}(not/downloads/{id})
7. Field Name Mapping
Common Field Changes
| Legacy API | New API |
|---|---|
transaction | check |
transaction_id | check_id |
tenant_id | Organization ID (in resource name) |
actor.name | subject.givenName + subject.familyName |
actor.phone | subject.phoneNumber |
actor.email | subject.email |
tasks | template + params |
status | state |
result | recommendation |
created_at | createTime |
updated_at | updateTime |
Status/State Mapping
| Legacy Status | New State |
|---|---|
open | ACTIVE |
closed | INACTIVE |
aborted | CANCELLED |
| N/A | DELETED |
Result/Recommendation Mapping
| Legacy Result | New Recommendation |
|---|---|
clear | CLEAR |
consider | CONSIDER |
fail | FAIL |
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
- Timestamps remain strings:
createTime,updateTimeuse ISO 8601 - Dates of birth: Convert to structured object with
year,month,day - 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
- No
actorvsexpectations: New API usessubjectfor all data - Structured address: Uses
buildingNumber,street,locality,postalCode,countryCode - Country code format:
GBR(ISO 3166-1 alpha-3) notGB(alpha-2) - Simplified: No need to omit fields or use
expectationsobject
10. Notifications Migration
The notification system has changed significantly between the legacy and new APIs.
Key Changes
| Aspect | Legacy API | New API |
|---|---|---|
| Scope | Per-transaction | Organization-level |
| Polling | Inbox-based with acknowledgment | Cursor-based pagination |
| Webhooks | Per-transaction configuration | Organization-level (managed by Thirdfort) |
| HMAC Key | Integrator-provided | Thirdfort-managed |
| Signature Header | X-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_tokenfor pagination (no acknowledgment) - Implement deduplication using notification IDs
Migration Steps:
- Remove inbox creation logic
- Remove per-check notification configuration
- Implement cursor-based polling with
nextPageToken - Replace acknowledgment with deduplication (store processed notification IDs)
- 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-Signatureheader (hexadecimal)
New: Organization-level webhooks
- Configured by Thirdfort at organization level
- Thirdfort-managed HMAC secret
- Signature in
x-thirdfort-signatureheader (base64)
Migration Steps:
- Contact api-support@thirdfort.com to configure webhooks
- Remove per-check webhook configuration from requests
- Update webhook endpoint to handle organization-level notifications
- Update signature verification:
- Change header from
X-Signaturetox-thirdfort-signature - Change format from hexadecimal to base64
- Use Thirdfort-provided secret
- Change header from
- Implement idempotency using notification IDs
- Test in nonproduction environment
Notification Types
The new API provides structured notification types:
notification.client.check_complete.v1- Check completednotification.client.report_generated.v1- Report generatednotification.client.ongoing_monitoring_hit.v1- Monitoring hit detectednotification.client.ongoing_monitoring_started.v1- Monitoring startednotification.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
Authorizationheader in PDF download requests - Use complete URL from
reportUrlfield - 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.mdfor step-by-step guide - Product Guides: See
products/directory for detailed product documentation - API Reference: Contact api@thirdfort.com for full API reference
Support
- Email: api@thirdfort.com
- Migration Assistance: Contact your account manager
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