Error Handling
The Partners API uses a standardized error handling approach to provide consistent, secure error responses without exposing internal system details.
Error Response Format
All API errors follow a consistent JSON structure:
{
"message": "Human-readable error message",
"code": "ERROR_CODE",
"statusCode": 400
}Response Fields
| Field | Type | Description |
|---|---|---|
message | string | Human-readable error description |
code | string | Standardized error code for programmatic handling |
statusCode | integer | HTTP status code |
Standard Error Codes
The API uses these standardized error codes across all endpoints:
| Code | Message | HTTP Status | Description |
|---|---|---|---|
VALIDATION_ERROR | "Invalid request parameters" | 400 | Invalid input data or failed validation |
AUTHENTICATION_ERROR | "Authentication required" | 401 | Missing or invalid Bearer token |
FORBIDDEN | "Access denied" | 403 | Attempting to access resources not owned by partner |
NOT_FOUND | "Resource not found" | 404 | Merchant, tag, or resource doesn't exist |
VALIDATION_ERROR | "DNS verification pending..." | 422 | DNS records not yet propagated (verification endpoint) |
SERVICE_ERROR | "Unable to process request" | 500 | Database errors or internal failures |
Authentication Errors
Authentication failures always return a consistent response to prevent information leakage:
{
"message": "Authentication required",
"code": "AUTHENTICATION_ERROR",
"statusCode": 401
}Common Authentication Issues
- Missing
Authorizationheader - Invalid Bearer token format (must be
Bearer mp_live_...) - Revoked or expired token
- Malformed token structure
Validation Errors
The API validates all request parameters using strict DTOs. Validation failures return:
{
"message": "Invalid request parameters",
"code": "VALIDATION_ERROR",
"statusCode": 400
}Common Validation Issues
- Missing required fields
- Invalid UUID format for IDs
- Invalid domain format (e.g., including protocol or www prefix)
- Out-of-range pagination values (page < 1 or limit > 100)
- Invalid data types
Resource Access Errors
Resource Not Found
When a requested resource doesn't exist:
{
"message": "Resource not found",
"code": "NOT_FOUND",
"statusCode": 404
}Access Denied
When attempting to access another partner's resources:
{
"message": "Access denied",
"code": "FORBIDDEN",
"statusCode": 403
}Special Error Cases
Some operations have specific error scenarios:
Domain Already Registered
When attempting to register a domain that's already in use:
{
"message": "Domain already registered",
"code": "VALIDATION_ERROR",
"statusCode": 409
}DNS Verification Pending
When DNS records haven't propagated yet during verification:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "DNS verification pending. Please allow time for DNS propagation and try again",
"statusCode": 422,
"timestamp": "2026-02-16T08:15:31.482Z",
"path": "/v1/partners/marktag/verify",
"method": "POST"
}
}DNS Verification Failed
When DNS record exists but points to an incorrect domain:
{
"message": "Tag verification failed. Please check your DNS configuration",
"code": "VALIDATION_ERROR",
"statusCode": 400
}Internal Server Errors
All database errors, external service failures, and unexpected errors return a generic response to prevent information leakage:
{
"message": "Unable to process request",
"code": "SERVICE_ERROR",
"statusCode": 500
}This includes:
- Database connection errors
- External service timeouts
- Unexpected application errors
- Configuration issues
Error Handling Best Practices
1. Use Error Codes for Logic
Always check the code field rather than parsing error messages:
// Good ✅
if (error.code === "AUTHENTICATION_ERROR") {
await refreshToken();
}
// Bad ❌
if (error.message.includes("Authentication")) {
await refreshToken();
}2. Implement Retry Logic
For transient failures, implement exponential backoff:
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (response.ok) return response;
const error = await response.json();
// Only retry on server errors
if (error.code === "SERVICE_ERROR" && i < maxRetries - 1) {
await new Promise((resolve) =>
setTimeout(resolve, Math.pow(2, i) * 1000),
);
continue;
}
throw error;
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
}Common Error Scenarios
Creating a Merchant
| Scenario | Error Code | Resolution |
|---|---|---|
| Missing merchant name | VALIDATION_ERROR | Provide a valid merchant name |
| Database issue | SERVICE_ERROR | Retry the request |
Generating MarkTag
| Scenario | Error Code | Resolution |
|---|---|---|
| Invalid domain format | VALIDATION_ERROR | Use format: example.com (no protocol/www) |
| Merchant doesn't exist | NOT_FOUND | Create merchant first |
| Domain already registered | VALIDATION_ERROR | Domain is already in use by another partner |
| Partner domain mismatch | VALIDATION_ERROR | Use your assigned partner domain for preverified tags |
Verifying MarkTag
| Scenario | Error Code | HTTP Status | Resolution |
|---|---|---|---|
| Tag doesn't exist | NOT_FOUND | 404 | Check tag ID is correct |
| DNS not propagated | VALIDATION_ERROR | 422 | Wait for DNS propagation (5-30 minutes typical) |
| DNS misconfigured | VALIDATION_ERROR | 400 | Check CNAME record configuration |
| Not your tag | FORBIDDEN | 403 | Can only verify tags you created |
| Server error | SERVICE_ERROR | 500 | Retry with exponential backoff |
Retrieving Events
| Scenario | Error Code | Resolution |
|---|---|---|
| Invalid date range | VALIDATION_ERROR | Use valid ISO 8601 date format |
| Page out of range | VALIDATION_ERROR | Use page number within valid range |
| Merchant not found | NOT_FOUND | Check merchant ID exists |
Troubleshooting Common Issues
MarkTag Not Tracking
Client-Side MarkTag
- Verify tagId is correct: Check the tagId matches what was returned from the API
- Check browser console: Look for JavaScript errors or blocked requests
- Ensure script placement: Script should be in the
<head>section of the page - Check for ad blockers: Some ad blockers may block tracking scripts
Server-Side MarkTag
- DNS verification fails: Confirm CNAME record is added correctly to merchant's DNS
- DNS propagation delay: Wait for full DNS propagation (typically 5-30 minutes, up to 48 hours in rare cases)
- Verify DNS setup: Use
nslookup mtag.domain.comto check DNS configuration - 422 error during verification: This is normal - DNS is still propagating, wait and retry
Preverified MarkTag
- Verify partner domain: Ensure your partner domain CNAME is properly configured
- Check domain usage: Confirm you're using the correct partner domain in tracking code
- Match tagId: Ensure tagId in tracking code matches the generated value
Event Collection Issues
- No events appearing: Verify the tracking script is loaded (check
typeof mtag === 'function'in console) - Delayed events: Events may take a few seconds to appear in the API
- Missing events: Check that events are being fired on the correct pages/actions
Support
If you encounter persistent errors or need assistance:
- Check your API token is valid and not expired
- Verify your request format matches the documentation
- Ensure DNS records are properly configured for domain verification
- Contact partners@markopolo.ai for technical support