Status Polling
After receiving the ae:complete event from the widget, poll the verification status from your backend server. Never expose your secret key (sk_verify_) in browser code.
Why Poll from the Backend?
The status and verified endpoints require a secret key (sk_verify_) which provides full API access including personal data (date of birth, document country). This key must never be sent to the browser. Your backend acts as a proxy between the browser and the AgeEvidence API.
Recommended Cadence
Use a progressive polling strategy to balance responsiveness with API efficiency:
- First 2 minutes: Poll every 5 seconds. This catches
age_onlyauto-decisions and fast admin reviews. - After 2 minutes: Poll every 30 seconds. Most manual reviews take 1-5 minutes.
- After 10 minutes: Stop polling and notify the user that review is in progress. Allow them to check back later.
Status Values
| Status | Terminal | Description |
|---|---|---|
pending | No | Verification submitted, waiting for admin review. |
under_review | No | An admin has opened the verification and is reviewing it. |
approved | Yes | Verification passed. Grant the user access. |
rejected | Yes | Verification failed. Deny access. |
resubmit_required | Yes | User needs to resubmit (e.g. blurry ID, incomplete liveness). Show the widget again. |
Stop polling when you receive a terminal status (approved, rejected, or resubmit_required).
Quick Check vs Full Status
Two endpoints are available depending on how much information you need:
- Quick check:
GET /v1/verify/:externalId/verifiedreturns{ verified: boolean }. Use this when you only need a pass/fail answer. - Full status:
GET /v1/verify/:externalId/statusreturns detailed information including DOB, estimated age, document country, and expiry date.
Backend Polling Example
A complete Node.js/Express example with progressive backoff:
const AGEEVIDENCE_API = 'https://ageevidence.com';
const SECRET_KEY = process.env.AGEEVIDENCE_SECRET_KEY; // sk_verify_...
// Proxy endpoint for your frontend
app.get('/api/check-verification', async (req, res) => {
const { externalId } = req.query;
const response = await fetch(
`${AGEEVIDENCE_API}/v1/verify/${externalId}/status`,
{
headers: { 'X-API-Key': SECRET_KEY },
}
);
if (!response.ok) {
return res.status(response.status).json({ error: 'Failed to check status' });
}
const data = await response.json();
res.json(data);
});
// Quick boolean check endpoint
app.get('/api/is-verified', async (req, res) => {
const { externalId } = req.query;
const response = await fetch(
`${AGEEVIDENCE_API}/v1/verify/${externalId}/verified`,
{
headers: { 'X-API-Key': SECRET_KEY },
}
);
if (!response.ok) {
return res.status(response.status).json({ error: 'Failed to check status' });
}
const data = await response.json();
res.json(data);
});Frontend Polling with Backoff
Call your own backend proxy (not the AgeEvidence API directly) from the browser:
async function pollVerificationStatus(externalId) {
const startTime = Date.now();
const TWO_MINUTES = 2 * 60 * 1000;
const TEN_MINUTES = 10 * 60 * 1000;
while (true) {
const elapsed = Date.now() - startTime;
// Stop after 10 minutes
if (elapsed > TEN_MINUTES) {
showMessage('Review in progress. Check back later.');
return;
}
const res = await fetch(`/api/check-verification?externalId=${externalId}`);
const { data } = await res.json();
if (data.status === 'approved') {
onVerificationApproved(data);
return;
}
if (data.status === 'rejected' || data.status === 'resubmit_required') {
onVerificationFailed(data);
return;
}
// Progressive backoff: 5s for first 2 min, then 30s
const delay = elapsed < TWO_MINUTES ? 5000 : 30000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}