This guide explains how to integrate the Contact Us API with your frontend website. It provides complete code examples for the three-step authentication and submission process.
The API uses a three-step process:
- Request a token when the form page loads
- Generate a signature server-side (keeps signing secret secure)
- Submit the contact form with token and signature
When the contact form page loads, request a token from the API:
async function loadContactForm() {
const response = await fetch('https://api.example.com/api/token', {
method: 'GET',
headers: {
'Origin': 'https://www.example.com'
}
});
const data = await response.json();
return data.token;
}Request a signature from the server. This keeps the signing secret secure on the backend.
async function generateSignature(name, email, message, token) {
const timestamp = Math.floor(Date.now() / 1000);
const response = await fetch('https://api.example.com/api/signature', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Origin': 'https://www.example.com'
},
body: JSON.stringify({
name,
email,
message,
token,
timestamp
})
});
const data = await response.json();
return data.signature;
}Submit the contact form with all required data:
async function submitContactForm(name, email, message, token) {
const timestamp = Math.floor(Date.now() / 1000);
// Generate signature server-side (keeps signing secret secure)
const signature = await generateSignature(name, email, message, token);
const response = await fetch('https://api.example.com/api/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Origin': 'https://www.example.com'
},
body: JSON.stringify({
name,
email,
message,
token,
signature,
timestamp
})
});
return await response.json();
}Here's a complete example that handles the entire flow:
async function handleContactFormSubmit(formData) {
try {
// Step 1: Get token
const tokenResponse = await fetch('https://api.example.com/api/token', {
method: 'GET',
headers: { 'Origin': 'https://www.example.com' }
});
const { token } = await tokenResponse.json();
// Step 2: Generate signature
const timestamp = Math.floor(Date.now() / 1000);
const signatureResponse = await fetch('https://api.example.com/api/signature', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Origin': 'https://www.example.com'
},
body: JSON.stringify({
name: formData.name,
email: formData.email,
message: formData.message,
token,
timestamp
})
});
const { signature } = await signatureResponse.json();
// Step 3: Submit form
const submitResponse = await fetch('https://api.example.com/api/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Origin': 'https://www.example.com'
},
body: JSON.stringify({
name: formData.name,
email: formData.email,
message: formData.message,
token,
signature,
timestamp
})
});
return await submitResponse.json();
} catch (error) {
console.error('Error submitting form:', error);
throw error;
}
}- Origin Header: Always include the
Originheader matching one of your allowed CORS origins (configured viaCONTACT_API_CORS_ALLOWED_ORIGINS). See Configuration Guide for details. - Token Expiration: Tokens expire after 5 minutes (default, configurable via
CONTACT_API_SECURITY_TOKEN_EXPIRY_SECONDS). Request a new token if the user takes too long to submit. - Error Handling: Always handle errors appropriately and provide user feedback.
- HTTPS: Use HTTPS in production to protect tokens and signatures in transit.
- Rate Limiting: Be aware of rate limits - tokens are limited per IP, submissions are limited per IP and origin. See Configuration Guide for rate limiting details.
The API returns standard HTTP status codes:
200: Success400: Invalid request data or missing fields401: Invalid or expired token403: Invalid signature or CORS violation429: Rate limit exceeded (checkRetry-Afterheader)500: Internal server error
Example error handling:
try {
const result = await submitContactForm(formData);
if (result.status === 'success') {
// Show success message
} else {
// Handle error
console.error('Submission failed:', result.message);
}
} catch (error) {
if (error.response?.status === 429) {
const retryAfter = error.response.headers.get('Retry-After');
console.error(`Rate limited. Retry after ${retryAfter} seconds`);
} else {
console.error('Error:', error);
}
}