GG Keywords API
v1StableProgrammatic access to Google Ads keyword research data and AI-powered keyword grouping. Built for agents, automation scripts, and third-party integrations.
Overview
Base URL
https://gg-keywords-workers-production.dongpt.workers.dev7
Endpoints
31
Locations
19
Languages
5,000
Max keywords/batch
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/keywords/research | Generate keyword ideas with metrics from Google Ads |
| POST | /api/v1/keywords/group | AI-powered keyword grouping (intent / topic / SEO) |
| GET | /api/v1/keywords/locations | List 31 supported geographic locations |
| GET | /api/v1/keywords/languages | List 19 supported languages |
| GET | /api/v1/quota | Check daily quota usage |
| GET | /api/v1/health | Health check with capabilities & rate limit info |
Quick Start
Get up and running in 3 steps:
1. Create an account
curl -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "your-password"}'2. Get an API key
# Login (saves auth cookie)
curl -c cookies.txt -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "your-password"}'
# Create API key
curl -b cookies.txt -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/keys \
-H "Content-Type: application/json" \
-d '{"name": "my-integration", "rateLimit": 30}'kkp_...) is shown only once at creation time and cannot be retrieved later.3. Make your first call
curl -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/keywords/research \
-H "Authorization: Bearer kkp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"keywords": ["email marketing"], "location": "US"}'Authentication
All /api/v1/* endpoints require an API key via the Authorization header:
Authorization: Bearer kkp_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2Key Format
API keys use the kkp_ prefix followed by 40 random hex characters (160 bits of entropy).
Key Management Endpoints
These require JWT cookie auth (login via browser or curl first):
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/keys | Create a new API key (max 5 per account) |
| GET | /api/keys | List active keys (prefix only, no full key) |
| DELETE | /api/keys/:id | Revoke a key (immediate, irreversible) |
curl -b cookies.txt -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/keys \
-H "Content-Type: application/json" \
-d '{"name": "production-agent", "rateLimit": 60}'{
"key": "kkp_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"prefix": "kkp_a1b2",
"name": "production-agent",
"rateLimit": 60,
"message": "Store this key securely. It will not be shown again."
}Security
The GG Keywords API is designed with multiple layers of security to protect your data and prevent abuse.
API Key Security
SHA-256 Key Hashing
API keys are hashed with SHA-256 before storage. We never store plaintext keys — even if our database is compromised, your key cannot be extracted.
One-Time Key Display
The full API key is returned exactly once at creation. It cannot be viewed again through the API or dashboard.
160-bit Entropy
Keys are generated using cryptographically secure random bytes (20 bytes = 160 bits), making brute-force attacks infeasible.
Instant Revocation
Compromised keys can be revoked immediately via DELETE /api/keys/:id. Revoked keys are rejected on the next request.
Key Limit
Maximum 5 active keys per account to minimize surface area. Rotate keys regularly by creating a new one and revoking the old.
Transport Security
HTTPS Only
All API traffic is served over HTTPS (TLS 1.2+) via Cloudflare's global edge network. HTTP requests are automatically redirected.
Cloudflare Edge Protection
Deployed on Cloudflare Workers with built-in DDoS protection, WAF, and bot management at the edge.
Rate Limiting & Abuse Prevention
Per-Key Rate Limiting
Each API key has its own sliding-window rate limit (configurable 1-120 requests/minute). One key cannot exhaust another's quota.
Per-IP Rate Limiting
Additional IP-based rate limiting (10 req/min) on management endpoints to prevent credential stuffing and brute-force attacks.
Daily Quota
1,000 keyword research requests per day to manage upstream Google Ads API costs. Cached results are free.
CORS Policy
Whitelist-Based CORS
Cross-origin requests are restricted to explicitly approved domains only. No wildcard * origins.
Data Security
No Data Sharing
Your keyword research data is isolated per account. We do not share, sell, or aggregate your research queries.
Cache Isolation
Cached keyword results are shared only when the exact same search parameters are used, reducing API costs for common queries.
Request Tracing
Every API response includes a unique requestId for debugging and audit purposes.
Keyword Research
/api/v1/keywords/researchGenerate keyword ideas with search volume, competition score, and CPC data from Google Ads API. Results are cached for 7 days.
| Parameter | Type | Required | Description |
|---|---|---|---|
| keywords | string[] | Required | Seed keywords (1+). Required if no url provided. |
| url | string | Optional | Seed URL (alternative to keywords). Takes precedence if both provided. |
| location | string | Optional ("US") | Country code, name, or Google Ads ID (e.g. "US", "United States", "2840") |
| language | string | Optional ("EN") | Language code, name, or Google Ads ID (e.g. "EN", "English", "1000") |
| includeAdultKeywords | boolean | Optional (false) | Include adult-oriented keywords in results |
curl -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/keywords/research \
-H "Authorization: Bearer kkp_your_key" \
-H "Content-Type: application/json" \
-d '{
"keywords": ["email marketing", "newsletter tools"],
"location": "US",
"language": "EN"
}'{
"success": true,
"data": {
"keywords": [
{
"keyword": "email marketing software",
"avgMonthlySearches": 22000,
"competition": "HIGH",
"competitionIndex": 87,
"lowTopOfPageBid": 5200000,
"highTopOfPageBid": 18500000
}
],
"totalResults": 150
},
"meta": {
"requestId": "a1b2c3d4e5f6a1b2",
"durationMs": 1842,
"fromCache": false,
"apiVersion": "v1"
},
"timestamp": "2026-02-25T12:00:00.000Z"
}Keyword Metrics Fields
| Field | Type | Description |
|---|---|---|
| keyword | string | The keyword text |
| avgMonthlySearches | integer | Average monthly search volume |
| competition | string | LOW, MEDIUM, HIGH, or UNSPECIFIED |
| competitionIndex | integer | 0-100 competition score |
| lowTopOfPageBid | integer | Low-range CPC in micros ($1 = 1,000,000) |
| highTopOfPageBid | integer | High-range CPC in micros ($1 = 1,000,000) |
"fromCache": true and do not count toward daily quota.Keyword Grouping
/api/v1/keywords/groupAI-powered keyword grouping with three modes. Powered by Claude AI.
| Parameter | Type | Required | Description |
|---|---|---|---|
| keywords | string[] | Required | Keywords to group (1-5,000) |
| mode | string | Required | "intent", "topic", or "seo" |
| keywordMetrics | KeywordMetrics[] | Optional | Required for SEO mode. Pass metrics from the research endpoint. |
intent Intent Mode
Classifies keywords by search intent: informational, transactional, navigational, commercial.
curl -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/keywords/group \
-H "Authorization: Bearer kkp_your_key" \
-H "Content-Type: application/json" \
-d '{
"keywords": ["buy running shoes", "how to start running", "nike store"],
"mode": "intent"
}'{
"success": true,
"data": {
"mode": "intent",
"groups": [
{ "keyword": "buy running shoes", "group": "transactional" },
{ "keyword": "how to start running", "group": "informational" },
{ "keyword": "nike store", "group": "navigational" }
],
"groupNames": ["transactional", "informational", "navigational"]
}
}topic Topic Mode
Groups keywords into semantic topic clusters.
curl -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/keywords/group \
-H "Authorization: Bearer kkp_your_key" \
-H "Content-Type: application/json" \
-d '{
"keywords": ["running shoes", "trail running gear", "marathon training plan", "5k race tips"],
"mode": "topic"
}'{
"success": true,
"data": {
"mode": "topic",
"groups": [
{ "keyword": "running shoes", "group": "Running Gear" },
{ "keyword": "trail running gear", "group": "Running Gear" },
{ "keyword": "marathon training plan", "group": "Race Training" },
{ "keyword": "5k race tips", "group": "Race Training" }
],
"groupNames": ["Running Gear", "Race Training"]
}
}seo SEO Mode
Maps keywords to URL clusters with intent, page type, and priority scoring. Requires keywordMetrics from the research endpoint.
curl -X POST https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/keywords/group \
-H "Authorization: Bearer kkp_your_key" \
-H "Content-Type: application/json" \
-d '{
"keywords": ["best running shoes 2026", "running shoe reviews"],
"mode": "seo",
"keywordMetrics": [
{
"keyword": "best running shoes 2026",
"avgMonthlySearches": 18000,
"competition": "HIGH",
"competitionIndex": 82,
"lowTopOfPageBid": 1200000,
"highTopOfPageBid": 3500000
},
{
"keyword": "running shoe reviews",
"avgMonthlySearches": 12000,
"competition": "MEDIUM",
"competitionIndex": 55,
"lowTopOfPageBid": 800000,
"highTopOfPageBid": 2100000
}
]
}'{
"success": true,
"data": {
"mode": "seo",
"assignments": [
{
"keyword": "best running shoes 2026",
"intent": "commercial",
"topic": "Running Shoes",
"urlCluster": "/best-running-shoes",
"pageType": "listicle"
},
{
"keyword": "running shoe reviews",
"intent": "informational",
"topic": "Running Shoes",
"urlCluster": "/best-running-shoes",
"pageType": "listicle"
}
],
"clusters": [
{
"urlCluster": "/best-running-shoes",
"intent": "commercial",
"topic": "Running Shoes",
"pageType": "listicle",
"suggestedSlug": "/best-running-shoes",
"keywords": ["best running shoes 2026", "running shoe reviews"],
"combinedVolume": 30000,
"avgCpc": 1.9,
"priority": 85
}
]
}
}Locations & Languages
/api/v1/keywords/locationsList all 31 supported geographic locations.
curl https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/keywords/locations \
-H "Authorization: Bearer kkp_your_key"{
"success": true,
"data": {
"locations": [
{ "code": "US", "id": "2840", "name": "United States" },
{ "code": "UK", "id": "2826", "name": "United Kingdom" },
{ "code": "DE", "id": "2276", "name": "Germany" },
{ "code": "JP", "id": "2392", "name": "Japan" },
{ "code": "VN", "id": "2704", "name": "Vietnam" }
],
"count": 31
}
}/api/v1/keywords/languagesList all 19 supported languages.
curl https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/keywords/languages \
-H "Authorization: Bearer kkp_your_key"{
"success": true,
"data": {
"languages": [
{ "code": "EN", "id": "1000", "name": "English" },
{ "code": "ES", "id": "1003", "name": "Spanish" },
{ "code": "JA", "id": "1005", "name": "Japanese" },
{ "code": "VI", "id": "1040", "name": "Vietnamese" }
],
"count": 19
}
}"US"), name ("United States"), or Google Ads ID ("2840").Quota & Rate Limits
Rate Limiting
Each API key has a configurable per-minute rate limit (1-120, default 30). Rate limit headers are included on every response:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed per minute |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | Unix timestamp (seconds) when window resets |
| Retry-After | Seconds to wait before retrying (only on 429) |
Daily Quota
Keyword research calls are limited to 1,000 requests per day. Quota resets at midnight UTC. Cached results do not count toward quota.
/api/v1/quotaCheck current daily quota usage.
curl https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/quota \
-H "Authorization: Bearer kkp_your_key"{
"success": true,
"data": {
"date": "2026-03-16",
"used": 42,
"limit": 1000,
"remaining": 958,
"resetAt": "2026-03-17T00:00:00.000Z",
"percentageUsed": 4.2
}
}/api/v1/healthHealth check with API capabilities and your key's rate limit config.
curl https://gg-keywords-workers-production.dongpt.workers.dev/api/v1/health \
-H "Authorization: Bearer kkp_your_key"{
"success": true,
"data": {
"status": "operational",
"capabilities": [
"keyword-research",
"keyword-grouping-intent",
"keyword-grouping-topic",
"keyword-grouping-seo",
"location-discovery",
"language-discovery",
"quota-check"
],
"rateLimit": {
"requestsPerMinute": 30,
"window": "60s"
},
"version": "1.0.0"
}
}Error Reference
Response Envelope
All responses follow a consistent envelope format:
{
"success": true,
"data": { ... },
"meta": {
"requestId": "a1b2c3d4e5f6a1b2",
"durationMs": 142,
"fromCache": false,
"apiVersion": "v1"
},
"timestamp": "2026-03-16T12:00:00.000Z"
}{
"success": false,
"data": null,
"error": "Human-readable error description",
"meta": {
"requestId": "a1b2c3d4e5f6a1b2",
"durationMs": 3,
"apiVersion": "v1"
},
"timestamp": "2026-03-16T12:00:00.000Z"
}HTTP Status Codes
| Status | Meaning | When |
|---|---|---|
| 200 | OK | Successful request |
| 201 | Created | API key created |
| 401 | Unauthorized | Missing, invalid, or revoked API key |
| 404 | Not Found | Unknown endpoint |
| 422 | Validation Error | Bad params, unknown location/language |
| 429 | Too Many Requests | Rate limit or daily quota exceeded |
| 500 | Internal Error | Unexpected server error |
| 502 | Bad Gateway | AI service (Claude) upstream failure |
| 503 | Service Unavailable | AI service not configured |
Error Codes
| Code | HTTP | Description |
|---|---|---|
| UNAUTHORIZED | 401 | Missing, invalid, or revoked API key |
| NOT_FOUND | 404 | Endpoint does not exist |
| VALIDATION_ERROR | 422 | Invalid request body or parameters |
| RATE_LIMITED | 429 | Per-minute rate limit exceeded |
| QUOTA_EXCEEDED | 429 | Daily quota limit reached |
| AI_SERVICE_ERROR | 502 | Claude AI call failed |
| INTERNAL_ERROR | 500 | Unhandled server error |
{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded: 60 requests per minute",
"details": {
"limit": 60,
"retryAfter": 12
}
}
}{
"success": false,
"error": {
"code": "QUOTA_EXCEEDED",
"message": "Daily quota exceeded: 1000/1000 requests used",
"details": {
"used": 1000,
"limit": 1000,
"resetAt": "2026-03-17T00:00:00.000Z"
}
}
}Best Practices
1. Store your API key securely
Use environment variables or a secrets manager. Never commit API keys to version control or expose them in client-side code.
2. Handle rate limits gracefully
Check X-RateLimit-Remaining headers. When you receive a 429, wait for the duration specified in the Retry-After header before retrying. Use exponential backoff for retries.
3. Leverage caching
Repeated requests with the same keywords + location + language return cached results instantly at no quota cost. Design your integration to benefit from this by batching similar queries.
4. Monitor quota usage
Call GET /api/v1/quota periodically to track your daily usage. Quota resets at midnight UTC.
5. Use specific locations & languages
Always specify location and language for the most relevant results. Use the discovery endpoints to find supported values.
6. Rotate API keys periodically
Create a new key, update your integration, then revoke the old key. You can have up to 5 active keys to enable zero-downtime rotation.
7. Batch keyword grouping
The grouping endpoint supports up to 5,000 keywords per request. Send larger batches to reduce the number of API calls.
8. Use requestId for debugging
Every response includes a unique meta.requestId. Include this when reporting issues for faster troubleshooting.
GG Keywords API v1 — Powered by Google Ads API & Claude AI
Deployed on Cloudflare Workers global edge network