API Documentation
//Getting Started
- 1Base URLAll endpoints are relative to https://verifyed.org/api/v1
- 2Make a RequestMost endpoints are public with no authentication required. Send a GET or POST request and receive JSON.
- 3Rate LimitsRequests are rate-limited per IP. Check X-RateLimit-* response headers for your current usage.
curl "https://verifyed.org/api/v1/search?q=springfield+high&country=US"//Search & Discovery
Search schools by name, CEEB code, or IB school code.
Full-text search across 912K+ government-sourced school records with optional country filtering. Supports direct CEEB and IB code lookups. Results are ranked by relevance and automatically cross-referenced against known diploma mills.
| Name | Type | Description |
|---|---|---|
q | string | Search query (min 2 characters). School name, partial name, or keyword. |
ceeb | string | CEEB code lookup (exactly 6 digits). Mutually exclusive with q and ib. |
ib | string | IB school code lookup (exactly 6 digits). Mutually exclusive with q and ceeb. |
country | string | ISO 3166-1 alpha-2 country codes, comma-separated. e.g. US or US,CA,GB |
limit | number= 20 | Results per page (1–100). |
offset | number= 0 | Pagination offset. |
include_all | boolean= false | Include non-high-school records (elementary, middle, etc.). |
group_dups | boolean= true | Group duplicate records from different data sources. |
qstring- Search query (min 2 characters). School name, partial name, or keyword.
ceebstring- CEEB code lookup (exactly 6 digits). Mutually exclusive with q and ib.
ibstring- IB school code lookup (exactly 6 digits). Mutually exclusive with q and ceeb.
countrystring- ISO 3166-1 alpha-2 country codes, comma-separated. e.g. US or US,CA,GB
limitnumber= 20- Results per page (1–100).
offsetnumber= 0- Pagination offset.
include_allboolean= false- Include non-high-school records (elementary, middle, etc.).
group_dupsboolean= true- Group duplicate records from different data sources.
curl "https://verifyed.org/api/v1/search?q=springfield+high&country=US&limit=5"{
"results": [
{
"id": "us-nces-170993000948",
"name": "Springfield High School",
"city": "Springfield",
"state_province": "IL",
"country_code": "US",
"source": "NCES",
"ceeb_code": "143280",
"verification_status": "verified",
"confidence_score": 0.9,
"match_score": 0.95
}
],
"total": 12,
"cached": false,
"diploma_mill_check": {
"is_match": false,
"confidence": 0
}
}Queries of exactly 6 digits are auto-detected as CEEB or IB code lookups.
Results include a diploma_mill_check object indicating whether the query matches any known diploma mills.
Fast prefix autocomplete for search-as-you-type UIs.
Optimized for dropdown speed. Returns lightweight results suitable for typeahead suggestions. Results are cached for 30–60 minutes depending on prefix length.
| Name | Type | Description |
|---|---|---|
q | string | Search prefix (min 2 characters). |
country | string | ISO 3166-1 alpha-2 country codes, comma-separated. |
state | string | State or province filter (uppercase). |
limit | number= 8 | Max results (1–10). |
include_all | boolean= false | Include non-high-school records. |
qstring- Search prefix (min 2 characters).
countrystring- ISO 3166-1 alpha-2 country codes, comma-separated.
statestring- State or province filter (uppercase).
limitnumber= 8- Max results (1–10).
include_allboolean= false- Include non-high-school records.
curl "https://verifyed.org/api/v1/autocomplete?q=spring&country=US&limit=5"{
"results": [
{
"id": "us-nces-170993000948",
"name": "Springfield High School",
"city": "Springfield",
"state_province": "IL",
"country_code": "US",
"ceeb_code": "143280",
"result_type": null
}
],
"cached": false,
"query_ms": 45
}//School Details
Get detailed school information including verification and enrichment data.
Returns the full school record with verification checks, accreditation data, enrichment results (geocoding, Street View, AI research), and metadata. Schools that haven’t been enriched recently may trigger automatic background enrichment.
| Name | Type | Description |
|---|---|---|
id | string | School ID (from search results). e.g. us-nces-170993000948 |
idstring- School ID (from search results). e.g. us-nces-170993000948
curl "https://verifyed.org/api/v1/schools/us-nces-170993000948"{
"id": "us-nces-170993000948",
"canonical_name": "Springfield High School",
"website": {
"url": "https://www.sps186.org/schools/SHS/",
"source": "government_data"
},
"address": {
"city": "Springfield",
"state": "IL",
"country": "US",
"coordinates": {
"lat": 39.7817,
"lng": -89.6501
}
},
"verification": {
"status": "verified",
"confidence_score": 0.9,
"checks": {
"government_registry": {
"status": "pass",
"details": "Found in NCES database"
},
"accreditation": {
"status": "pass",
"details": "NCA accredited"
}
}
},
"metadata": {
"school_type": "High School",
"grade_levels": "9-12",
"enrollment": 1850,
"ceeb_code": "143280",
"source": "NCES",
"data_year": 2023,
"operating_status": "Open"
},
"accreditations": [
{
"accreditor_name": "NCA",
"accreditor_type": "Regional",
"status": "active"
}
],
"enrichment_pending": false
}The response shape varies based on enrichment level. Newly discovered schools may have fewer fields until enrichment completes.
//Enrichment
Trigger enrichment to add verification data to a school record.
Kicks off background enrichment jobs that add geocoding, Street View imagery, address validation, and AI-powered research to a school record. Jobs run asynchronously by default — poll the job status endpoint to track progress.
| Name | Type | Description |
|---|---|---|
id | string | School ID to enrich. |
level | string= standard | Enrichment depth. "basic" = geocoding + address only. "standard" = adds Street View + AI research. "deep" = full research with fraud analysis. |
idstring- School ID to enrich.
levelstring= standard- Enrichment depth. "basic" = geocoding + address only. "standard" = adds Street View + AI research. "deep" = full research with fraud analysis.
curl -X POST "https://verifyed.org/api/v1/schools/us-nces-170993000948/enrich?level=standard"{
"status": "queued",
"job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"estimated_time_seconds": 30
}If X-API-Key is provided and matches ENRICHMENT_API_KEY, auth checks pass. Without a key, the endpoint may still work if no key is configured server-side.
Use level="deep" sparingly — it consumes more AI credits and takes longer.
Check the status of an enrichment job.
Poll this endpoint to track enrichment progress. Jobs transition through queued → running → completed (or failed).
| Name | Type | Description |
|---|---|---|
job_id | string | Job ID returned from the enrich endpoint. |
job_idstring- Job ID returned from the enrich endpoint.
curl "https://verifyed.org/api/v1/jobs/f47ac10b-58cc-4372-a567-0e02b2c3d479"{
"job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "completed",
"school_id": "us-nces-170993000948",
"level": "standard",
"started_at": "2025-01-20T10:30:00Z",
"completed_at": "2025-01-20T10:30:28Z",
"error_message": null,
"sources_checked": [
"geocoding",
"street_view",
"address_validation",
"perplexity_research"
]
}//AI Research
AI-powered fraud research for an unverified school name.
Uses Perplexity AI to research a school name and assess its legitimacy. Returns fraud risk indicators, red flags, sources, and an actionable recommendation. Results are cached for 7 days.
| Name | Type | Description |
|---|---|---|
name | string | School name to research (min 2 characters). |
city | string | City to narrow the search. |
country | string | Country to narrow the search. |
namestring- School name to research (min 2 characters).
citystring- City to narrow the search.
countrystring- Country to narrow the search.
curl -X POST "https://verifyed.org/api/v1/research-school" \
-H "Content-Type: application/json" \
-d '{"name": "Pacific Coast Academy", "country": "US"}'{
"found_online": true,
"confidence": "high",
"fraud_risk": "low",
"red_flags": [],
"sources": [
{
"url": "https://example.com/school-page",
"title": "Pacific Coast Academy - Official Site"
}
],
"recommendation": "School appears legitimate with verified online presence and accreditation records.",
"generated_at": "2025-01-20T10:30:00Z",
"cached": false
}This endpoint calls external AI APIs and may take 5–15 seconds to respond on cache miss.
Results are cached for 7 days based on normalized name + city + country.
//Platform
Database coverage statistics and enrichment metrics.
curl "https://verifyed.org/api/v1/stats"{
"database": {
"total_schools": 184350,
"country_count": 50,
"by_country": [
{
"country_code": "US",
"count": 120000
},
{
"country_code": "GB",
"count": 8500
}
],
"by_school_type": [
{
"school_type": "Public",
"count": 150000
},
{
"school_type": "Private",
"count": 34350
}
],
"diploma_mills_tracked": 2592
},
"enrichment": {
"jobs_last_24h": {
"completed": 1250,
"failed": 3
}
},
"generated_at": "2025-01-20T10:30:00Z",
"cached": true
}Stats are cached for 10 minutes. The first request after cache expiry may be slower.
Health check for database and cache dependencies.
curl "https://verifyed.org/api/v1/health"{
"status": "healthy",
"timestamp": "2025-01-20T10:30:00Z",
"version": "1.0.0",
"checks": {
"database": "ok",
"cache": "ok"
}
}//API Key Management (Admin)
Create a new API key.
Issues a new API key with the specified tier. The plaintext key is returned only once in the response — store it securely. The key is stored as a SHA-256 hash and cannot be recovered.
| Name | Type | Description |
|---|---|---|
name | string | Human-readable label for the key (e.g. "Acme Corp production"). |
owner_email | string | Contact email for the key owner. |
tier | string= free | Rate limit tier: free, pro, or internal. |
expires_at | string | ISO 8601 expiry date. Omit for no expiry. |
namestring- Human-readable label for the key (e.g. "Acme Corp production").
owner_emailstring- Contact email for the key owner.
tierstring= free- Rate limit tier: free, pro, or internal.
expires_atstring- ISO 8601 expiry date. Omit for no expiry.
curl -X POST "https://verifyed.org/api/v1/admin/api-keys" \
-H "X-Backfill-Key: YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Acme Corp", "owner_email": "dev@acme.com", "tier": "pro"}'{
"id": "550e8400-e29b-41d4-a716-446655440000",
"key": "sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
"key_prefix": "sk_live_a1b2",
"name": "Acme Corp",
"tier": "pro"
}Requires admin authentication via X-Backfill-Key header or ?key= query parameter.
The 'key' field is only returned at creation time. Store it immediately.
List API keys with pagination and filtering.
| Name | Type | Description |
|---|---|---|
limit | number= 20 | Results per page (1–100). |
offset | number= 0 | Pagination offset. |
is_active | boolean | Filter by active (true) or revoked (false) keys. |
limitnumber= 20- Results per page (1–100).
offsetnumber= 0- Pagination offset.
is_activeboolean- Filter by active (true) or revoked (false) keys.
curl "https://verifyed.org/api/v1/admin/api-keys?limit=10&is_active=true" \
-H "X-Backfill-Key: YOUR_ADMIN_KEY"{
"results": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"key_prefix": "sk_live_a1b2",
"name": "Acme Corp",
"owner_email": "dev@acme.com",
"tier": "pro",
"is_active": 1,
"last_used_at": "2026-02-07T15:30:00Z",
"request_count": 1250,
"created_at": "2026-01-15T10:00:00Z",
"revoked_at": null,
"expires_at": null
}
],
"total": 5
}Get details for a specific API key.
| Name | Type | Description |
|---|---|---|
id | string | API key UUID. |
idstring- API key UUID.
curl "https://verifyed.org/api/v1/admin/api-keys/550e8400-e29b-41d4-a716-446655440000" \
-H "X-Backfill-Key: YOUR_ADMIN_KEY"{
"id": "550e8400-e29b-41d4-a716-446655440000",
"key_prefix": "sk_live_a1b2",
"name": "Acme Corp",
"owner_email": "dev@acme.com",
"tier": "pro",
"scopes": "[\"read\"]",
"is_active": 1,
"last_used_at": "2026-02-07T15:30:00Z",
"request_count": 1250,
"created_at": "2026-01-15T10:00:00Z",
"revoked_at": null,
"expires_at": null
}Update an API key's name, tier, or active status.
| Name | Type | Description |
|---|---|---|
id | string | API key UUID. |
idstring- API key UUID.
| Name | Type | Description |
|---|---|---|
name | string | New label for the key. |
tier | string | New tier: free, pro, or internal. |
is_active | boolean | Set to false to revoke the key. |
namestring- New label for the key.
tierstring- New tier: free, pro, or internal.
is_activeboolean- Set to false to revoke the key.
curl -X PATCH "https://verifyed.org/api/v1/admin/api-keys/550e8400-..." \
-H "X-Backfill-Key: YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"tier": "internal"}'{
"updated": true
}Revoke an API key (soft delete).
Marks the key as inactive and records the revocation timestamp. The key record is preserved for audit purposes. Cached key data is immediately invalidated.
| Name | Type | Description |
|---|---|---|
id | string | API key UUID to revoke. |
idstring- API key UUID to revoke.
curl -X DELETE "https://verifyed.org/api/v1/admin/api-keys/550e8400-..." \
-H "X-Backfill-Key: YOUR_ADMIN_KEY"{
"revoked": true
}Revocation takes effect within 5 minutes (KV cache TTL). For immediate effect, the cache is proactively invalidated.
//Common Patterns
Rate Limiting
Rate-limited endpoints include these headers when rate limiting is applied:
| Name | Type | Description |
|---|---|---|
X-RateLimit-Limit | header | Maximum requests allowed in the current window. |
X-RateLimit-Remaining | header | Requests remaining in the current window. |
X-RateLimit-Reset | header | Unix timestamp (seconds) when the window resets. |
X-RateLimit-Limitheader- Maximum requests allowed in the current window.
X-RateLimit-Remainingheader- Requests remaining in the current window.
X-RateLimit-Resetheader- Unix timestamp (seconds) when the window resets.
Rate limits may vary by endpoint and deployment. Always check response headers for accurate current limits rather than relying on documentation values.
{
"error": "Rate limit exceeded",
"retry_after_seconds": 42
}Error Responses
All errors return a JSON object with an error field:
{
"error": "School not found"
}| Name | Type | Description |
|---|---|---|
400 | status | Invalid request parameters or missing required fields. |
404 | status | Resource not found. |
429 | status | Rate limit exceeded. Check retry_after_seconds in the response. |
500 | status | Internal server error. |
400status- Invalid request parameters or missing required fields.
404status- Resource not found.
429status- Rate limit exceeded. Check retry_after_seconds in the response.
500status- Internal server error.
Authentication
API keys are optional but unlock higher rate limits. Pass your key via the X-API-Key header on every request.
curl -H "X-API-Key: sk_live_a1b2c3d4..." "https://verifyed.org/api/v1/search?q=test"| Tier | Search | Autocomplete | Enrichment | Description |
|---|---|---|---|---|
| Anonymous | 100 / min | 120 / min | 10 / min | No API key (default) |
| Free | 300 / min | 400 / min | 30 / min | Free-tier API key |
| Pro | 1,000 / min | 1,500 / min | 100 / min | Pro-tier API key |
| Internal | 5,000 / min | 5,000 / min | 500 / min | Internal use |
Admin endpoints (API key management) require the X-Backfill-Key header instead of X-API-Key.