Workflow: Handle 409 Conflicts
Learn how to handle conflicts when linking clients who already exist in Debitura's system through other channels.
Understanding 409 Conflicts
A 409 Conflict response occurs when you attempt to link a client that already has a relationship with Debitura through another channel:
- Direct customer account
- Another referral partner
- Collection partner relationship
- Legacy system migration
When Conflicts Occur
Conflicts can happen during:
- Client Linking - Attempting to create a new linked client
- Case Creation - Creating a case for a debtor already known to Debitura
- Onboarding - Customer already completed onboarding elsewhere
Conflict Response Structure
When a conflict occurs, you'll receive a 409 Conflict response with detailed information:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error": {
"type": "conflict_error",
"message": "Client already exists in Debitura system",
"conflict_type": "existing_client",
"details": {
"client_id": "cli_existing_123",
"relationship_type": "direct_customer",
"created_at": "2023-06-15T08:30:00Z",
"can_claim": false,
"claim_deadline": null
}
}
}
Conflict Types
1. Existing Direct Customer
Scenario: Company already has a direct Debitura account.
Response:
{
"error": {
"type": "conflict_error",
"conflict_type": "existing_direct_customer",
"details": {
"client_id": "cli_abc123",
"relationship_type": "direct_customer",
"can_claim": false
}
}
}
Resolution:
- Contact Debitura support to discuss migration
- Customer must approve transfer to referral model
- Existing cases remain with direct relationship
2. Existing Referral Partner
Scenario: Company already linked to a different referral partner.
Response:
{
"error": {
"type": "conflict_error",
"conflict_type": "existing_referral_partner",
"details": {
"client_id": "cli_abc123",
"relationship_type": "referral_partner",
"partner_name": "Other Platform AB",
"can_claim": false
}
}
}
Resolution:
- Cannot claim clients from other partners
- Customer must terminate existing relationship first
- Debitura support can facilitate if needed
3. Claimable Client
Scenario: Company exists but is in an inactive or transitional state that allows claiming.
Response:
{
"error": {
"type": "conflict_error",
"conflict_type": "claimable_client",
"details": {
"client_id": "cli_abc123",
"relationship_type": "inactive",
"can_claim": true,
"claim_deadline": "2024-02-15T23:59:59Z"
}
}
}
Resolution: Use the claim endpoint (see below).
Claiming Clients
When can_claim: true is indicated, you can claim the client:
Claim Request
POST /v1/referral-partners/clients/{client_id}/claim
Request:
{
"external_id": "your_customer_id_123",
"acknowledge_terms": true,
"metadata": {
"claim_reason": "customer_migrated",
"migration_date": "2024-01-15"
}
}
Response:
{
"client_id": "cli_abc123",
"external_id": "your_customer_id_123",
"status": "active",
"bearer_token": "tok_new_xyz789",
"claimed_at": "2024-01-15T10:00:00Z",
"previous_relationship": "inactive"
}
Claim Conditions
You can claim a client when:
- Client is marked as
can_claim: true - Claim deadline has not passed
- You acknowledge attribution terms
- No active referral partner relationship exists
What Happens After Claiming
-
Attribution Changes
- Future cases attributed to you
- Existing case attribution unchanged
- Clear separation of old vs new cases
-
Bearer Token Issued
- New bearer token for case creation
- Old credentials (if any) remain for historical access
-
Audit Trail
- Claim recorded in client history
- Previous relationship noted
- Revenue attribution adjusted
Handling Strategies
Strategy 1: Graceful Degradation
Provide degraded functionality when client cannot be linked:
async function linkOrDegrade(customerData) {
try {
const client = await linkClient(customerData);
return {
linked: true,
bearer_token: client.bearer_token,
features: ['case_creation', 'revenue_share']
};
} catch (error) {
if (error.status === 409) {
// Client exists, but we can't link them
return {
linked: false,
features: ['manual_referral'], // Limited functionality
message: 'Contact support to complete setup'
};
}
throw error;
}
}
Strategy 2: Support-Assisted Resolution
Direct customer to support when conflicts arise:
async function handleConflict(error, customerData) {
if (error.conflict_type === 'existing_direct_customer') {
// Generate support ticket
const ticket = await createSupportTicket({
type: 'client_migration',
customer: customerData,
conflict_details: error.details
});
return {
action: 'contact_support',
ticket_id: ticket.id,
message: 'We need to migrate your existing Debitura account. Support will contact you within 24 hours.'
};
}
}
Strategy 3: Claim When Possible
Automatically claim when permitted:
async function linkOrClaim(customerData) {
try {
// Attempt normal linking
return await linkClient(customerData);
} catch (error) {
if (error.status === 409 && error.details.can_claim) {
// Automatically claim if allowed
return await claimClient(
error.details.client_id,
customerData.external_id
);
}
throw error;
}
}
Preventing Conflicts
Pre-Flight Validation
Check if a client exists before attempting to link:
GET /v1/referral-partners/validate-client?vat_number=SE123456789001
Response:
{
"exists": true,
"available_for_linking": false,
"conflict_type": "existing_direct_customer",
"recommendations": [
"contact_support",
"customer_approval_required"
]
}
Validation Workflow
- Before Linking: Call validation endpoint
- If Available: Proceed with linking
- If Conflict: Show appropriate message to user
- If Claimable: Offer claim option
Error Response Reference
Common Conflict Scenarios
| Scenario | conflict_type | can_claim | Action |
|---|---|---|---|
| Direct customer | existing_direct_customer | false | Contact support |
| Other partner | existing_referral_partner | false | Cannot link |
| Inactive account | claimable_client | true | Use claim endpoint |
| Pending onboarding | pending_onboarding | true | Complete or claim |
| Terminated account | terminated_account | true | Claim within deadline |
Best Practices
User Experience
- Clearly communicate conflict situations
- Provide actionable next steps
- Avoid technical jargon in error messages
- Offer support contact information
Technical Implementation
- Implement pre-flight validation
- Handle 409s gracefully
- Log conflict occurrences
- Monitor conflict patterns
Business Process
- Document conflict resolution process
- Train support team on migration
- Set customer expectations
- Track time-to-resolution
Examples
Example 1: Check Before Link
async function safelyLinkClient(customerData) {
// Pre-flight check
const validation = await validateClient({
vat_number: customerData.vat_number,
email: customerData.email
});
if (!validation.available_for_linking) {
// Handle conflict proactively
return {
success: false,
reason: validation.conflict_type,
action_required: validation.recommendations
};
}
// Safe to link
return await linkClient(customerData);
}
Example 2: Automatic Claim Flow
async function linkWithAutoClaim(customerData) {
try {
return await linkClient(customerData);
} catch (error) {
if (error.status === 409) {
const { can_claim, client_id } = error.details;
if (can_claim) {
// Automatically claim
console.log('Client exists but is claimable, claiming...');
return await claimClient(client_id, {
external_id: customerData.external_id,
acknowledge_terms: true
});
}
// Cannot claim - escalate
throw new Error(
`Cannot link client: ${error.conflict_type}. Please contact support.`
);
}
throw error;
}
}
Support Escalation
When conflicts cannot be resolved automatically:
-
Gather Information
- Client details from your system
- Conflict error response
- Customer's intent/preference
-
Contact Debitura Support
- Email: partners@debitura.com
- Include: client_id, conflict details
- Timeline: 24-48 hour response
-
Customer Communication
- Inform customer of situation
- Set expectations on timeline
- Provide tracking information
Next Steps
- Bearer Token Model - Understand token security
- Client Linking Workflow - Full linking guide
- Troubleshooting - Common issues and solutions