VeroID

Best Practices

Recommendations for integrating VeroID

Security

Server-Side Only

Never call the VeroID API from client-side code:

// ✅ DO: Server-side API route
export async function POST(req) {
  const data = await req.json();
  const result = await fetch('https://api.veroid.com.au/v1/verify', {
    headers: { 'X-API-Key': process.env.VEROID_API_KEY },
    body: JSON.stringify(data),
  });
  return result.json();
}

Store Keys in Environment Variables

// ✅ DO: Use environment variables
const apiKey = process.env.VEROID_API_KEY;

// ❌ DON'T: Hardcode keys
const apiKey = 'sk_live_abc123...';

Error Handling

Implement Retries

Only S (system error) responses are transient and safe to retry. Y, N, and D are definitive outcomes - do not retry them. HTTP 429 document cooldowns and DVS_DOCUMENT_LOCKED responses also require waiting - honour Retry-After rather than retrying in a tight loop (see below).

async function verifyWithRetry(data, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const result = await verify(data);

    // Y, N, D are definitive - return immediately
    if (result.status !== 'error') return result;

    // S = system error at issuer or DVS Hub - safe to retry with backoff
    if (result.responseCode === 'S') {
      await sleep(1000 * Math.pow(2, attempt));
      continue;
    }

    return result;
  }
}

Document lockout and repeat submissions

DVS and issuing agencies limit how often the same document can be verified in a short period. If a user fixes a typo and clicks verify again immediately, or your integration auto-retries unchanged document data, the issuer may temporarily lock that document.

This applies to live verification only. Sandbox does not enforce document cooldowns.

  • Do not resubmit the same document details in quick succession - wait for the user to correct their input, then submit once
  • Do not auto-retry N or D outcomes with the same payload
  • Honour the Retry-After header on HTTP 429 responses
  • Debounce verify buttons and disable repeat submits while a request is in flight

VeroID applies two live protections before and after a DVS lock:

CodeHTTPWhen
DOCUMENT_COOLDOWN429The same document was submitted again within about 1 minute
DVS_DOCUMENT_LOCKED500DVS or the issuer returned "Document Temporarily Locked" - wait about 5 minutes before retrying the same document
const response = await fetch('https://api.veroid.com.au/v1/verify', { ... });
const result = await response.json();

if (response.status === 429 && result.code === 'DOCUMENT_COOLDOWN') {
  const waitSeconds = Number(response.headers.get('Retry-After') ?? result.retryAfterSeconds);
  // Show the user a "please wait" message - do not retry immediately
  return;
}

if (response.status === 500 && result.code === 'DVS_DOCUMENT_LOCKED') {
  const waitSeconds = Number(response.headers.get('Retry-After') ?? result.retryAfterSeconds);
  // DVS locked this document - wait before submitting the same details again
  return;
}

Handle All Outcomes

const result = await verify(data);

switch (result.responseCode) {
  case 'Y':
    // Data matches the issuer record
    break;
  case 'N':
    // Data does not match - check result.errors for field-level detail
    if (result.errors?.length) {
      console.log(result.errors[0].field, result.errors[0].message);
    }
    break;
  case 'D':
    // Data error at the issuer (record not held at source)
    break;
  case 'S':
    // System error - may retry
    break;
}

Expanded Responses

When DVS returns field-level detail (VersionNumber=2), it appears in the errors array on the POST response. Capture it at verification time - it is not stored and cannot be retrieved later via GET. See the API reference.

  • Surface errors[].message to help users correct mistyped fields
  • Use errors[].field to highlight the relevant form input when present
  • Do not treat N or D as HTTP errors - they are valid verification outcomes
  • Do not retry N or D; only S is transient

Compliance

Data Handling

  • Don't store PII longer than necessary
  • Don't log sensitive document numbers
  • Do store verification IDs for audit trails
// ✅ DO: Log verification ID only
logger.info('Verification completed', { 
  verificationId: result.verificationId,
  status: result.status 
});

// ❌ DON'T: Log PII
logger.info('Verification', { 
  name: data.givenName,
  licenceNumber: data.licenceNumber 
});