Fetch Customer
The Fetch Customer endpoint retrieves detailed information about a specific customer using their unique identifier. This endpoint is essential for customer profile displays, transaction processing workflows, and customer service operations. It provides complete customer data with associated application information and automatic audit logging.
Endpoint DetailsCopied!
-
Method:
GET
-
URL:
/api/v0/customers/{id}
-
Content Type: Not applicable (GET request)
-
Authentication: Required (
x-client-key
andx-client-secret
) -
Rate Limiting: Subject to standard API rate limits
Path ParametersCopied!
Parameter |
Type |
Required |
Description |
Constraints |
---|---|---|---|---|
|
string |
✅ |
Unique customer identifier (UUID) |
Must be valid UUID format |
Request HeadersCopied!
x-client-key: your_client_key_here
x-client-secret: your_client_secret_here
Request ExampleCopied!
GET /api/v0/customers/550e8400-e29b-41d4-a716-446655440000 HTTP/1.1
Host: api.devdraft.com
x-client-key: your_client_key
x-client-secret: your_client_secret
Success ResponseCopied!
Status Code: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"phone_number": "+1-555-123-4567",
"customer_type": "Individual",
"status": "ACTIVE",
"last_spent": 250.75,
"last_purchase_date": "2024-01-10T15:30:00Z",
"appId": "app_123456789",
"app_id": "app_123456789",
"createdAt": "2024-01-01T10:00:00Z",
"updatedAt": "2024-01-15T14:30:00Z",
"app": {
"id": "app_123456789",
"app_name": "My Application"
}
}
Response Field Descriptions
Field |
Type |
Description |
Nullable |
---|---|---|---|
|
string |
Customer's unique identifier (UUID) |
❌ |
|
string |
Customer's first name |
❌ |
|
string |
Customer's last name |
❌ |
|
string |
Customer's email address |
✅ |
|
string |
Customer's phone number with country code |
❌ |
|
string |
Account type (Individual, Business, Enterprise, Non-Profit) |
✅ |
|
string |
Account status (ACTIVE, BLACKLISTED, DEACTIVATED) |
❌ |
|
number |
Amount of most recent transaction |
❌ |
|
string |
ISO 8601 timestamp of last purchase |
✅ |
|
string |
Associated application identifier |
❌ |
|
string |
Duplicate field for backward compatibility |
❌ |
|
string |
ISO 8601 timestamp when customer was created |
❌ |
|
string |
ISO 8601 timestamp when customer was last updated |
❌ |
|
object |
Associated application details |
❌ |
Customer Status Values
-
"ACTIVE"
- Customer can access all services -
"BLACKLISTED"
- Customer is blocked from services -
"DEACTIVATED"
- Customer account is deactivated
Customer Type Values
-
"Individual"
- Personal customer account -
"Business"
- Business customer account -
"Enterprise"
- Enterprise-level customer -
"Non-Profit"
- Non-profit organization
Error ResponsesCopied!
Customer Not Found (404)
{
"statusCode": 404,
"message": "Customer not found",
"error": "Not Found"
}
Invalid UUID Format (400)
{
"statusCode": 400,
"message": "Invalid UUID format",
"error": "Bad Request"
}
Authentication Error (401)
{
"statusCode": 401,
"message": "Invalid API credentials",
"error": "Unauthorized"
}
Access Denied (403)
{
"statusCode": 403,
"message": "Customer does not belong to your application",
"error": "Forbidden"
}
Rate Limit Exceeded (429)
{
"statusCode": 429,
"message": "Too many requests",
"error": "Too Many Requests",
"retry_after": 60
}
Server Error (500)
{
"statusCode": 500,
"message": "Internal server error",
"error": "Internal Server Error"
}
Integration ExamplesCopied!
cURL
curl -X GET https://api.devdraft.com/api/v0/customers/550e8400-e29b-41d4-a716-446655440000 \
-H "x-client-key: your_client_key" \
-H "x-client-secret: your_client_secret"
JavaScript/Node.js
Basic Implementation
async function fetchCustomer(customerId) {
const response = await fetch(`https://api.devdraft.com/api/v0/customers/${customerId}`, {
headers: {
'x-client-key': process.env.DEVDRAFT_CLIENT_KEY,
'x-client-secret': process.env.DEVDRAFT_CLIENT_SECRET
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
}
// Usage
try {
const customer = await fetchCustomer('550e8400-e29b-41d4-a716-446655440000');
console.log(`Customer: ${customer.first_name} ${customer.last_name}`);
} catch (error) {
console.error('Failed to fetch customer:', error.message);
}
With Error Handling
async function getCustomerSafely(customerId) {
try {
const response = await fetch(`https://api.devdraft.com/api/v0/customers/${customerId}`, {
headers: {
'x-client-key': process.env.DEVDRAFT_CLIENT_KEY,
'x-client-secret': process.env.DEVDRAFT_CLIENT_SECRET
}
});
if (response.status === 404) {
return null; // Customer not found
}
if (response.status === 403) {
throw new Error('Access denied: Customer belongs to different application');
}
if (!response.ok) {
throw new Error(`API Error: ${response.status} ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error(`Error fetching customer ${customerId}:`, error.message);
throw error;
}
}
// Usage with null checking
const customer = await getCustomerSafely('550e8400-e29b-41d4-a716-446655440000');
if (customer) {
console.log('Customer found:', customer.email);
} else {
console.log('Customer not found');
}
Customer Service Helper
class CustomerService {
constructor(clientKey, clientSecret) {
this.baseUrl = 'https://api.devdraft.com/api/v0/customers';
this.headers = {
'x-client-key': clientKey,
'x-client-secret': clientSecret
};
}
async getCustomer(id) {
const response = await fetch(`${this.baseUrl}/${id}`, {
headers: this.headers
});
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `HTTP ${response.status}`);
}
return await response.json();
}
async getCustomerDisplay(id) {
const customer = await this.getCustomer(id);
return {
id: customer.id,
name: `${customer.first_name} ${customer.last_name}`,
email: customer.email,
phone: customer.phone_number,
status: customer.status,
type: customer.customer_type,
lastSpent: customer.last_spent,
joinDate: new Date(customer.createdAt).toLocaleDateString()
};
}
async isCustomerActive(id) {
try {
const customer = await this.getCustomer(id);
return customer.status === 'ACTIVE';
} catch (error) {
if (error.message.includes('404')) {
return false;
}
throw error;
}
}
}
// Usage
const customerService = new CustomerService(
process.env.DEVDRAFT_CLIENT_KEY,
process.env.DEVDRAFT_CLIENT_SECRET
);
const displayData = await customerService.getCustomerDisplay('550e8400-e29b-41d4-a716-446655440000');
console.log('Customer Display:', displayData);
Python
Basic Implementation
import requests
import os
from typing import Optional, Dict
class DevdraftCustomer:
def __init__(self):
self.base_url = "https://api.devdraft.com/api/v0/customers"
self.headers = {
'x-client-key': os.getenv('DEVDRAFT_CLIENT_KEY'),
'x-client-secret': os.getenv('DEVDRAFT_CLIENT_SECRET')
}
def get_customer(self, customer_id: str) -> Optional[Dict]:
"""Fetch a customer by ID."""
try:
response = requests.get(
f"{self.base_url}/{customer_id}",
headers=self.headers
)
if response.status_code == 404:
return None
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error fetching customer {customer_id}: {e}")
raise
def get_customer_summary(self, customer_id: str) -> Optional[Dict]:
"""Get customer with formatted summary data."""
customer = self.get_customer(customer_id)
if not customer:
return None
return {
'id': customer['id'],
'full_name': f"{customer['first_name']} {customer['last_name']}",
'contact': {
'email': customer.get('email'),
'phone': customer['phone_number']
},
'account': {
'type': customer.get('customer_type', 'Individual'),
'status': customer['status'],
'created': customer['createdAt'],
'last_updated': customer['updatedAt']
},
'activity': {
'last_spent': customer['last_spent'],
'last_purchase': customer.get('last_purchase_date')
}
}
def verify_customer_access(self, customer_id: str) -> bool:
"""Verify if customer exists and is accessible."""
try:
customer = self.get_customer(customer_id)
return customer is not None
except Exception:
return False
# Usage examples
client = DevdraftCustomer()
# Basic fetch
customer = client.get_customer('550e8400-e29b-41d4-a716-446655440000')
if customer:
print(f"Found customer: {customer['first_name']} {customer['last_name']}")
# Get formatted summary
summary = client.get_customer_summary('550e8400-e29b-41d4-a716-446655440000')
if summary:
print(f"Customer: {summary['full_name']}")
print(f"Status: {summary['account']['status']}")
print(f"Last spent: ${summary['activity']['last_spent']}")
Advanced Error Handling
import requests
from typing import Optional, Dict, Union
from dataclasses import dataclass
from datetime import datetime
@dataclass
class CustomerError:
code: int
message: str
customer_id: str
class CustomerAPI:
def __init__(self, client_key: str, client_secret: str):
self.base_url = "https://api.devdraft.com/api/v0/customers"
self.headers = {
'x-client-key': client_key,
'x-client-secret': client_secret
}
def get_customer(self, customer_id: str) -> Union[Dict, CustomerError]:
"""
Fetch customer with comprehensive error handling.
Returns customer dict on success, CustomerError on failure.
"""
try:
response = requests.get(
f"{self.base_url}/{customer_id}",
headers=self.headers,
timeout=10
)
if response.status_code == 404:
return CustomerError(404, "Customer not found", customer_id)
elif response.status_code == 403:
return CustomerError(403, "Access denied", customer_id)
elif response.status_code == 401:
return CustomerError(401, "Invalid credentials", customer_id)
elif response.status_code == 429:
return CustomerError(429, "Rate limit exceeded", customer_id)
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
return CustomerError(408, "Request timeout", customer_id)
except requests.exceptions.ConnectionError:
return CustomerError(503, "Connection error", customer_id)
except requests.exceptions.RequestException as e:
return CustomerError(500, f"Request failed: {str(e)}", customer_id)
def get_customer_safe(self, customer_id: str) -> Optional[Dict]:
"""Get customer, return None on any error."""
result = self.get_customer(customer_id)
return result if isinstance(result, dict) else None
# Usage with error handling
api = CustomerAPI(
os.getenv('DEVDRAFT_CLIENT_KEY'),
os.getenv('DEVDRAFT_CLIENT_SECRET')
)
result = api.get_customer('550e8400-e29b-41d4-a716-446655440000')
if isinstance(result, CustomerError):
print(f"Error {result.code}: {result.message}")
else:
print(f"Customer: {result['first_name']} {result['last_name']}")
PHP
Basic Implementation
<?php
class DevdraftCustomer {
private $baseUrl = 'https://api.devdraft.com/api/v0/customers';
private $headers;
public function __construct($clientKey, $clientSecret) {
$this->headers = [
'x-client-key: ' . $clientKey,
'x-client-secret: ' . $clientSecret
];
}
public function getCustomer($customerId) {
$url = $this->baseUrl . '/' . $customerId;
$context = stream_context_create([
'http' => [
'method' => 'GET',
'header' => implode("\r\n", $this->headers),
'timeout' => 10
]
]);
$result = @file_get_contents($url, false, $context);
if ($result === false) {
// Check if it was a 404
if (isset($http_response_header)) {
foreach ($http_response_header as $header) {
if (strpos($header, '404') !== false) {
return null; // Customer not found
}
}
}
throw new Exception('Failed to fetch customer');
}
return json_decode($result, true);
}
public function getCustomerSafe($customerId) {
try {
return $this->getCustomer($customerId);
} catch (Exception $e) {
error_log("Failed to fetch customer $customerId: " . $e->getMessage());
return null;
}
}
public function formatCustomerDisplay($customerId) {
$customer = $this->getCustomer($customerId);
if (!$customer) {
return null;
}
return [
'id' => $customer['id'],
'name' => $customer['first_name'] . ' ' . $customer['last_name'],
'email' => $customer['email'] ?? 'N/A',
'phone' => $customer['phone_number'],
'status' => $customer['status'],
'type' => $customer['customer_type'] ?? 'Individual',
'last_spent' => '$' . number_format($customer['last_spent'], 2),
'join_date' => date('M j, Y', strtotime($customer['createdAt']))
];
}
public function isActiveCustomer($customerId) {
$customer = $this->getCustomerSafe($customerId);
return $customer && $customer['status'] === 'ACTIVE';
}
}
// Usage
$client = new DevdraftCustomer(
$_ENV['DEVDRAFT_CLIENT_KEY'],
$_ENV['DEVDRAFT_CLIENT_SECRET']
);
$customerId = '550e8400-e29b-41d4-a716-446655440000';
// Basic fetch
$customer = $client->getCustomer($customerId);
if ($customer) {
echo "Customer: " . $customer['first_name'] . " " . $customer['last_name'] . "\n";
}
// Formatted display
$display = $client->formatCustomerDisplay($customerId);
if ($display) {
echo "Display Name: " . $display['name'] . "\n";
echo "Status: " . $display['status'] . "\n";
echo "Last Spent: " . $display['last_spent'] . "\n";
}
// Check if active
if ($client->isActiveCustomer($customerId)) {
echo "Customer is active\n";
}
?>
Advanced Use CasesCopied!
Customer Profile Component
// React component for customer profile
import { useState, useEffect } from 'react';
function CustomerProfile({ customerId }) {
const [customer, setCustomer] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function loadCustomer() {
try {
setLoading(true);
const response = await fetch(`/api/customers/${customerId}`);
if (response.status === 404) {
setError('Customer not found');
return;
}
if (!response.ok) {
throw new Error('Failed to load customer');
}
const data = await response.json();
setCustomer(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
if (customerId) {
loadCustomer();
}
}, [customerId]);
if (loading) return <div>Loading customer...</div>;
if (error) return <div>Error: {error}</div>;
if (!customer) return <div>Customer not found</div>;
return (
<div className="customer-profile">
<h2>{customer.first_name} {customer.last_name}</h2>
<div className="customer-details">
<p><strong>Email:</strong> {customer.email || 'Not provided'}</p>
<p><strong>Phone:</strong> {customer.phone_number}</p>
<p><strong>Type:</strong> {customer.customer_type || 'Individual'}</p>
<p><strong>Status:</strong>
<span className={`status-${customer.status.toLowerCase()}`}>
{customer.status}
</span>
</p>
<p><strong>Last Purchase:</strong>
${customer.last_spent.toFixed(2)} on{' '}
{customer.last_purchase_date
? new Date(customer.last_purchase_date).toLocaleDateString()
: 'Never'
}
</p>
<p><strong>Member since:</strong>
{new Date(customer.createdAt).toLocaleDateString()}
</p>
</div>
</div>
);
}
Customer Validation Service
from typing import Dict, List, Optional
import re
class CustomerValidator:
def __init__(self, api_client):
self.api = api_client
def validate_customer_for_transaction(self, customer_id: str, amount: float) -> Dict:
"""Validate customer eligibility for a transaction."""
customer = self.api.get_customer(customer_id)
if not customer:
return {
'valid': False,
'reason': 'Customer not found',
'code': 'CUSTOMER_NOT_FOUND'
}
if customer['status'] != 'ACTIVE':
return {
'valid': False,
'reason': f"Customer status is {customer['status']}",
'code': 'CUSTOMER_INACTIVE'
}
# Business logic validations
if customer['status'] == 'BLACKLISTED':
return {
'valid': False,
'reason': 'Customer is blacklisted',
'code': 'CUSTOMER_BLACKLISTED'
}
# Additional validations based on amount
if amount > 10000 and not customer.get('email'):
return {
'valid': False,
'reason': 'Email required for high-value transactions',
'code': 'EMAIL_REQUIRED'
}
return {
'valid': True,
'customer': customer,
'code': 'VALID'
}
def get_customer_risk_profile(self, customer_id: str) -> Dict:
"""Assess customer risk profile."""
customer = self.api.get_customer(customer_id)
if not customer:
return {'risk_level': 'UNKNOWN', 'reason': 'Customer not found'}
risk_factors = []
risk_score = 0
# Check account age
from datetime import datetime
created = datetime.fromisoformat(customer['createdAt'].replace('Z', '+00:00'))
days_old = (datetime.now().replace(tzinfo=created.tzinfo) - created).days
if days_old < 30:
risk_factors.append('New account (less than 30 days)')
risk_score += 2
# Check transaction history
if customer['last_spent'] == 0:
risk_factors.append('No transaction history')
risk_score += 3
elif customer['last_spent'] > 5000:
risk_factors.append('High-value transaction history')
risk_score += 1
# Check contact information
if not customer.get('email'):
risk_factors.append('No email address')
risk_score += 1
# Determine risk level
if risk_score >= 5:
risk_level = 'HIGH'
elif risk_score >= 3:
risk_level = 'MEDIUM'
else:
risk_level = 'LOW'
return {
'risk_level': risk_level,
'risk_score': risk_score,
'risk_factors': risk_factors,
'customer_id': customer_id
}
# Usage
validator = CustomerValidator(api_client)
# Validate for transaction
validation = validator.validate_customer_for_transaction(
'550e8400-e29b-41d4-a716-446655440000',
1500.00
)
if validation['valid']:
print("Customer approved for transaction")
else:
print(f"Transaction denied: {validation['reason']}")
# Get risk profile
risk = validator.get_customer_risk_profile('550e8400-e29b-41d4-a716-446655440000')
print(f"Customer risk level: {risk['risk_level']}")
Performance ConsiderationsCopied!
Response Times
-
Average response time: 50-150ms
-
99th percentile: <300ms
-
Timeout recommendation: 10 seconds
Caching Strategy
class CustomerCache {
constructor(ttl = 300000) { // 5 minutes default
this.cache = new Map();
this.ttl = ttl;
}
async getCustomer(id, fetchFunction) {
if (this.cache.has(id)) {
const cached = this.cache.get(id);
if (Date.now() < cached.expiry) {
return cached.data;
}
this.cache.delete(id);
}
const customer = await fetchFunction(id);
if (customer) {
this.cache.set(id, {
data: customer,
expiry: Date.now() + this.ttl
});
}
return customer;
}
invalidate(id) {
this.cache.delete(id);
}
clear() {
this.cache.clear();
}
}
// Usage
const cache = new CustomerCache();
const customer = await cache.getCustomer(customerId, fetchCustomer);
Security ConsiderationsCopied!
Data Access Control
-
Customers are automatically scoped to your application
-
Cannot access customers from other applications
-
All requests require valid API credentials
Audit Logging
-
Every customer fetch is automatically logged for compliance
-
Includes user information, timestamp, and request metadata
-
Access patterns monitored for security anomalies
Privacy Protection
-
Sensitive data encrypted at rest and in transit
-
Compliant with GDPR, CCPA, and other privacy regulations
-
Audit trails maintained for data access
Best PracticesCopied!
1. Error Handling
Always implement comprehensive error handling for different scenarios:
async function safeGetCustomer(id) {
try {
const customer = await fetchCustomer(id);
return { success: true, data: customer };
} catch (error) {
if (error.message.includes('404')) {
return { success: false, error: 'CUSTOMER_NOT_FOUND' };
}
if (error.message.includes('403')) {
return { success: false, error: 'ACCESS_DENIED' };
}
return { success: false, error: 'UNKNOWN_ERROR', details: error.message };
}
}
2. Input Validation
Validate UUID format before making API calls:
function isValidUUID(str) {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return uuidRegex.test(str);
}
3. Caching Strategy
Cache customer data appropriately based on your use case:
-
Profile pages: 5-15 minutes
-
Transaction processing: 1-5 minutes
-
Admin dashboards: 30 seconds to 2 minutes
4. Rate Limiting
Implement client-side rate limiting to avoid API limits:
class RateLimitedAPI {
constructor(maxRequests = 100, windowMs = 3600000) {
this.requests = [];
this.maxRequests = maxRequests;
this.windowMs = windowMs;
}
async makeRequest(requestFn) {
const now = Date.now();
this.requests = this.requests.filter(time => now - time < this.windowMs);
if (this.requests.length >= this.maxRequests) {
throw new Error('Rate limit exceeded');
}
this.requests.push(now);
return await requestFn();
}
}
Related EndpointsCopied!
-
GET /api/v0/customers
- List customers with filtering and pagination -
POST /api/v0/customers
- Create new customers -
PATCH /api/v0/customers/{id}
- Update customer information -
POST /api/v0/customers/{id}/liquidation_addresses
- Manage customer liquidation addresses
SupportCopied!
For technical support or questions about fetching customers:
-
Ensure customer ID is a valid UUID format
-
Verify the customer belongs to your application
-
Check your API credentials and permissions
-
Contact support with the specific customer ID and error details for faster assistance