The FirstQuadrant API uses URL-based versioning to ensure backward compatibility while allowing for continuous improvement. This guide explains our versioning strategy and how to handle version changes.
Current version
The current API version is v5, accessible at:
https://api.us.firstquadrant.ai/v5
URL versioning
API versions are included in the URL path:
# Current version
https://api.us.firstquadrant.ai/v5/contacts
# Previous versions (deprecated)
https://api.us.firstquadrant.ai/v4/contacts
https://api.us.firstquadrant.ai/v3/contacts
Every API response includes a Version
header with detailed version information:
Version: firstquadrant.ai-2024-01-15-a1b2c3d4
Format: firstquadrant.ai-YYYY-MM-DD-{commitHash}
This header provides:
- Date: When this version was deployed
- Commit Hash: The exact code version running
Version lifecycle
Version support policy
Version | Status | Support End Date | Notes |
---|
v5 | Current | - | Latest features and improvements |
v4 | Deprecated | 2024-12-31 | Security fixes only |
v3 | End of Life | 2023-12-31 | No longer available |
Deprecation timeline
- Announcement: 6 months before deprecation
- Deprecation: Version marked as deprecated, security fixes only
- End of Life: 12 months after deprecation announcement
- Removal: API version no longer accessible
Breaking vs non-breaking changes
Non-breaking changes (no version change)
These changes are made without incrementing the API version:
- Adding new endpoints
- Adding new optional fields to responses
- Adding new optional parameters to requests
- Adding new values to enums (when the client can handle unknown values)
- Performance improvements
- Bug fixes
Breaking changes (new version required)
These changes require a new API version:
- Removing endpoints
- Removing or renaming fields
- Changing field types
- Changing authentication methods
- Modifying validation rules
- Changing error response formats
- Removing enum values
Checking your API version
Via cURL
curl -I https://api.us.firstquadrant.ai/v5/me \
-H "Authorization: Bearer YOUR_API_KEY"
# Response headers include:
# Version: firstquadrant.ai-2024-01-15-a1b2c3d4
Programmatically
const response = await fetch("https://api.us.firstquadrant.ai/v5/me", {
headers: {
Authorization: "Bearer YOUR_API_KEY",
},
});
const version = response.headers.get("Version");
console.log("API Version:", version);
Migration guide
Preparing for version changes
- Monitor Deprecation Notices: Subscribe to API changelog
- Test Early: Use staging environment to test new versions
- Gradual Migration: Update services incrementally
- Version Abstraction: Implement version handling in your client
Version abstraction pattern
class FirstQuadrantClient {
constructor(config) {
this.apiKey = config.apiKey;
this.version = config.version || "v5";
this.baseUrl = `https://api.us.firstquadrant.ai/${this.version}`;
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
Authorization: `Bearer ${this.apiKey}`,
"Content-Type": "application/json",
...options.headers,
},
});
// Log version for monitoring
console.log("API Version:", response.headers.get("Version"));
return response;
}
// Version-specific handling
async getContacts(params) {
switch (this.version) {
case "v5":
return this.getContactsV5(params);
case "v4":
return this.getContactsV4(params);
default:
throw new Error(`Unsupported API version: ${this.version}`);
}
}
async getContactsV5(params) {
// v5 implementation with new features
const queryParams = new URLSearchParams({
...params,
// v5 supports advanced filtering
"filter.status.equals": params.status,
});
return this.request(`/contacts?${queryParams}`);
}
async getContactsV4(params) {
// v4 implementation with compatibility layer
const queryParams = new URLSearchParams({
...params,
// v4 uses different parameter format
status: params.status,
});
return this.request(`/contacts?${queryParams}`);
}
}
Version-specific changes
v5 (Current)
Released: January 2024
New Features:
- Advanced filtering with dot notation
- Cursor-based pagination improvements
- Enhanced field selection
- Batch operation support
- Improved error responses
Breaking Changes from v4:
- Filter syntax changed from
filter[field][op]
to filter.field.op
- Removed deprecated
/legacy
endpoints
- Standardized ID prefixes across all resources
v4 to v5 migration
Filter syntax update
// v4 syntax
const v4Params = {
"filter[email][contains]": "@example.com",
"filter[tags][has]": "customer",
};
// v5 syntax
const v5Params = {
"filter.email.contains": "@example.com",
"filter.tags.has": "customer",
};
// Migration helper
function migrateFilters(v4Filters) {
const v5Filters = {};
for (const [key, value] of Object.entries(v4Filters)) {
// Convert filter[field][op] to filter.field.op
const match = key.match(/^filter\[([^\]]+)\]\[([^\]]+)\]$/);
if (match) {
const [, field, op] = match;
v5Filters[`filter.${field}.${op}`] = value;
} else {
v5Filters[key] = value;
}
}
return v5Filters;
}
// v4 response wrapper
{
"success": true,
"data": [...],
"meta": {
"total": 100,
"page": 1
}
}
// v5 response (direct array)
[
{ "id": "con_123", "email": "[email protected]" },
{ "id": "con_456", "email": "[email protected]" }
]
// Migration adapter
function adaptV4Response(v5Response, endpoint) {
if (endpoint.includes('/count')) {
return v5Response; // Count endpoint unchanged
}
if (Array.isArray(v5Response)) {
return {
success: true,
data: v5Response,
meta: {
count: v5Response.length
}
};
}
return {
success: true,
data: v5Response
};
}
Testing version compatibility
Version-specific test suite
describe("API Version Compatibility", () => {
const versions = ["v4", "v5"];
versions.forEach((version) => {
describe(`API ${version}`, () => {
let client;
beforeEach(() => {
client = new FirstQuadrantClient({
apiKey: process.env.TEST_API_KEY,
version,
});
});
it("should fetch contacts", async () => {
const contacts = await client.getContacts({
status: "active",
});
expect(contacts).toBeDefined();
// Version-specific assertions
if (version === "v4") {
expect(contacts).toHaveProperty("data");
} else {
expect(Array.isArray(contacts)).toBe(true);
}
});
});
});
});
Compatibility checker
async function checkApiCompatibility(version) {
const tests = [
{
name: "Authentication",
endpoint: "/me",
method: "GET",
},
{
name: "List Contacts",
endpoint: "/contacts",
method: "GET",
},
{
name: "Filtering",
endpoint: "/[email protected]",
method: "GET",
},
];
const results = [];
for (const test of tests) {
try {
const response = await fetch(`https://api.us.firstquadrant.ai/${version}${test.endpoint}`, {
method: test.method,
headers: {
Authorization: `Bearer ${API_KEY}`,
},
});
results.push({
test: test.name,
status: response.ok ? "PASS" : "FAIL",
statusCode: response.status,
});
} catch (error) {
results.push({
test: test.name,
status: "ERROR",
error: error.message,
});
}
}
return results;
}
Staying updated
API changelog
Monitor changes through:
- Changelog: docs.firstquadrant.ai/changelog
- Email Notifications: Subscribe to API updates
- Version Header: Monitor the
Version
header for changes
Webhooks for version changes
Subscribe to version change notifications:
{
"event": "api.version.deprecated",
"version": "v4",
"deprecationDate": "2024-06-01",
"endOfLifeDate": "2024-12-31",
"migrationGuide": "https://docs.firstquadrant.ai/migration/v4-to-v5"
}
Best practices
1. Explicit version declaration
Always explicitly specify the API version:
// ✅ Good: Explicit version
const API_VERSION = "v5";
const API_BASE = `https://api.us.firstquadrant.ai/${API_VERSION}`;
// ❌ Bad: Implicit latest version
const API_BASE = "https://api.us.firstquadrant.ai/latest";
2. Version configuration
Make version configurable:
// config.js
export const config = {
api: {
version: process.env.FIRSTQUADRANT_API_VERSION || "v5",
key: process.env.FIRSTQUADRANT_API_KEY,
baseUrl: process.env.FIRSTQUADRANT_API_URL || "https://api.us.firstquadrant.ai",
},
};
3. Gradual migration
Implement feature flags for version migration:
class VersionedClient {
async getContacts(params) {
if (featureFlags.useV5Api) {
return this.v5.getContacts(params);
} else {
return this.v4.getContacts(params);
}
}
}
4. Monitor version usage
Track which versions your application uses:
class APIClient {
constructor() {
this.metrics = {
versionUsage: {},
};
}
async request(version, endpoint) {
// Track version usage
this.metrics.versionUsage[version] = (this.metrics.versionUsage[version] || 0) + 1;
// Make request
const response = await fetch(`https://api.us.firstquadrant.ai/${version}${endpoint}`);
// Log version from response
console.log(`Used API ${version}, Server: ${response.headers.get("Version")}`);
return response;
}
}
Summary
- Current Version: v5
- Version in URL:
https://api.us.firstquadrant.ai/v5
- Version Header: Included in all responses
- Support Period: 12+ months after deprecation
- Migration Notice: 6 months before changes
- Best Practice: Always use explicit versioning
Stay informed about version changes and plan migrations early to ensure smooth transitions between API versions.