Skip to main content
POST
/
identities
/
:id
/
detokenize
curl -X POST https://YOUR_BLNK_INSTANCE_URL/identities/idt_1234567890/detokenize \
  -H "Content-Type: application/json" \
  -H "X-Blnk-Key: YOUR_API_KEY" \
  -d '{
    "fields": ["email_address", "phone_number"]
  }'
{
  "fields": {
    "EmailAddress": "john.doe@example.com",
    "PhoneNumber": "+1234567890"
  }
}
Retrieves the original, unencrypted values of multiple tokenized fields in a single operation. If no fields are specified, all tokenized fields are detokenized.

Path Parameters

id
string
required
The unique identifier of the identity

Request Body

fields
array
Array of field names to detokenize. If empty or omitted, all tokenized fields will be detokenized.Example: ["email_address", "phone_number"]

Response

fields
object
Map of field names to their original, unencrypted values
curl -X POST https://YOUR_BLNK_INSTANCE_URL/identities/idt_1234567890/detokenize \
  -H "Content-Type: application/json" \
  -H "X-Blnk-Key: YOUR_API_KEY" \
  -d '{
    "fields": ["email_address", "phone_number"]
  }'
{
  "fields": {
    "EmailAddress": "john.doe@example.com",
    "PhoneNumber": "+1234567890"
  }
}

Behavior

Specific Fields Mode

When you provide a fields array with specific field names:
{
  "fields": ["email_address", "phone_number"]
}
  • Only the specified fields are detokenized
  • Each field must be currently tokenized
  • If any field is not tokenized, an error is returned
  • Processing stops at the first error

All Fields Mode

When you provide an empty fields array or omit it entirely:
{
  "fields": []
}
or
{}
  • All tokenized fields are automatically detokenized
  • The system checks meta_data.tokenized_fields to find which fields are tokenized
  • Returns a map of all tokenized field names to their original values
  • Fields that are not tokenized are not included in the response

Security Considerations

Critical Security Notice: This endpoint retrieves multiple PII fields in plain text. Implement the strictest access controls and comprehensive audit logging.

Access Control Requirements

  1. Minimal Privilege: Only grant access to users who absolutely need it
  2. Multi-Factor Authentication: Require MFA for all users with access
  3. IP Whitelisting: Restrict access to specific IP addresses
  4. Time-Based Access: Implement temporary access windows
  5. Approval Workflow: Require manager approval for detokenization requests

Audit Logging

Log every detokenization request with:
{
  "event": "DETOKENIZE_MULTIPLE_FIELDS",
  "timestamp": "2024-01-15T10:30:00Z",
  "user_id": "usr_admin123",
  "user_email": "admin@company.com",
  "user_role": "compliance_officer",
  "identity_id": "idt_1234567890",
  "fields_requested": ["email_address", "phone_number"],
  "fields_returned": ["EmailAddress", "PhoneNumber"],
  "ip_address": "192.168.1.100",
  "user_agent": "Mozilla/5.0...",
  "justification": "Fraud investigation case #12345",
  "session_id": "sess_xyz789"
}

Compliance Requirements

Ensure compliance with data protection regulations:
  • GDPR Article 32: Implement appropriate security measures
  • GDPR Article 30: Maintain records of processing activities
  • PCI DSS Requirement 7: Restrict access to cardholder data
  • HIPAA § 164.308: Implement access controls for PHI

Use Cases

Customer Service Investigation

// Support agent needs to verify customer details
const { fields } = await detokenizeFields(
  'idt_1234567890',
  ['email_address', 'phone_number']
);

console.log(`Customer Email: ${fields.EmailAddress}`);
console.log(`Customer Phone: ${fields.PhoneNumber}`);

Fraud Investigation

// Fraud team needs all customer information
const { fields } = await detokenizeFields(
  'idt_suspicious123',
  [] // Detokenize all fields
);

// Analyze all available PII
const fullProfile = {
  name: `${fields.FirstName} ${fields.LastName}`,
  email: fields.EmailAddress,
  phone: fields.PhoneNumber,
  address: `${fields.Street}, ${fields.PostCode}`
};

Regulatory Audit

// Compliance officer conducting audit
const { fields } = await detokenizeFields(
  'idt_audit456',
  ['email_address', 'street', 'post_code']
);

// Generate audit report
const auditReport = {
  identity_id: 'idt_audit456',
  contact_email: fields.EmailAddress,
  registered_address: `${fields.Street}, ${fields.PostCode}`,
  audit_date: new Date(),
  auditor: currentUser.email
};

Data Export for Customer Request

// Customer requests their personal data (GDPR right of access)
const identity = await getIdentity('idt_1234567890');
const { fields: detokenizedFields } = await detokenizeFields(
  identity.identity_id,
  [] // All fields
);

// Merge with identity data
const exportData = {
  ...identity,
  ...detokenizedFields,
  export_date: new Date(),
  export_reason: 'customer_data_request'
};

Implementation Examples

With Audit Logging

async function detokenizeWithAudit(identityId, fields, userId, justification) {
  // Create audit log entry
  const auditId = await auditLog.create({
    action: 'DETOKENIZE_MULTIPLE_FIELDS',
    userId: userId,
    identityId: identityId,
    fieldsRequested: fields,
    justification: justification,
    timestamp: new Date(),
    ipAddress: request.ip,
    userAgent: request.headers['user-agent']
  });
  
  try {
    // Perform detokenization
    const response = await fetch(
      `https://YOUR_BLNK_INSTANCE_URL/identities/${identityId}/detokenize`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Blnk-Key': 'YOUR_API_KEY'
        },
        body: JSON.stringify({ fields })
      }
    );
    
    const data = await response.json();
    
    // Update audit log with success
    await auditLog.update(auditId, {
      status: 'success',
      fieldsReturned: Object.keys(data.fields)
    });
    
    return data;
  } catch (error) {
    // Update audit log with failure
    await auditLog.update(auditId, {
      status: 'failed',
      error: error.message
    });
    
    throw error;
  }
}

With Approval Workflow

async function requestDetokenization(identityId, fields, reason) {
  // Create approval request
  const request = await approvalWorkflow.create({
    type: 'DETOKENIZE_PII',
    requestedBy: currentUser.id,
    identityId: identityId,
    fields: fields,
    reason: reason,
    status: 'pending'
  });
  
  // Notify approvers
  await notifyApprovers(request);
  
  return {
    message: 'Detokenization request submitted for approval',
    requestId: request.id,
    estimatedApprovalTime: '1-2 hours'
  };
}

async function approveDetokenization(requestId, approverId) {
  const request = await approvalWorkflow.get(requestId);
  
  // Verify approver has permission
  if (!hasApprovalPermission(approverId)) {
    throw new Error('Insufficient permissions to approve');
  }
  
  // Update request status
  await approvalWorkflow.update(requestId, {
    status: 'approved',
    approvedBy: approverId,
    approvedAt: new Date()
  });
  
  // Perform detokenization
  const result = await detokenizeFields(
    request.identityId,
    request.fields
  );
  
  // Notify requester
  await notifyRequester(request, result);
  
  return result;
}

Error Handling

Sequential Processing

When detokenizing specific fields, processing stops at the first error:
// Request to detokenize 3 fields
const fields = ['email_address', 'phone_number', 'street'];

// If phone_number is not tokenized:
// - email_address is successfully detokenized
// - Error returned for phone_number
// - street is not processed

Recovery Strategy

async function detokenizeWithRecovery(identityId, fields) {
  try {
    return await detokenizeFields(identityId, fields);
  } catch (error) {
    if (error.message.includes('is not tokenized')) {
      // Get list of actually tokenized fields
      const { tokenized_fields } = await getTokenizedFields(identityId);
      
      // Retry with only tokenized fields
      const validFields = fields.filter(f => 
        tokenized_fields.includes(f) || 
        tokenized_fields.includes(capitalize(f))
      );
      
      if (validFields.length > 0) {
        return await detokenizeFields(identityId, validFields);
      }
    }
    
    throw error;
  }
}

Performance Considerations

  • Decryption Time: ~10-20ms per field
  • Database Queries: 1 query to fetch identity
  • Network Overhead: One HTTP request regardless of field count
  • Recommended Batch Size: Up to 10 fields per request

Optimization Tips

  1. Cache Detokenized Values: For read-heavy workflows, cache values temporarily
  2. Batch Requests: Process multiple identities in parallel
  3. Request Only Needed Fields: Don’t use “all fields” mode unless necessary

Monitoring and Alerts

Set up monitoring for:
  • Volume Alerts: >100 detokenization requests per hour
  • Failed Attempts: >5 failures from same user/IP
  • Unusual Patterns: Detokenization outside business hours
  • Bulk Operations: Same user detokenizing >50 identities

Comparison: Specific vs All Fields

AspectSpecific FieldsAll Fields
Request Body{"fields": ["email_address"]}{"fields": []} or {}
BehaviorDetokenizes only specified fieldsDetokenizes all tokenized fields
Error HandlingFails if field not tokenizedOnly returns tokenized fields
Use CaseTargeted accessComplete data export
Security RiskLower (minimal exposure)Higher (full PII exposure)
Recommendation: Always request specific fields unless you have a legitimate need for all PII data.

Build docs developers (and LLMs) love