optbrew 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +6 -0
- package/.claude-plugin/plugin.json +6 -0
- package/.codex-plugin/plugin.json +13 -0
- package/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/README.ko.md +73 -0
- package/README.md +72 -2
- package/THIRD_PARTY_NOTICES.md +10 -0
- package/bin/optbrew.mjs +4 -0
- package/docs/platforms.md +31 -0
- package/docs/release.md +14 -0
- package/lib/cli.mjs +103 -0
- package/lib/doctor.mjs +44 -0
- package/lib/install.mjs +158 -0
- package/lib/paths.mjs +30 -0
- package/lib/records.mjs +44 -0
- package/lib/transaction.mjs +205 -0
- package/lib/update.mjs +181 -0
- package/package.json +39 -4
- package/plugin.json +13 -0
- package/skills/optbrew/LICENSE +21 -0
- package/skills/optbrew/SKILL.md +17 -0
- package/skills/optbrew/THIRD_PARTY_NOTICES.md +10 -0
- package/skills/optbrew/agents/openai.yaml +4 -0
- package/skills/optbrew/bundle-manifest.json +663 -0
- package/skills/optbrew/licenses/firecrawl-seo-audit.txt +15 -0
- package/skills/optbrew/licenses/magnus-seo.txt +21 -0
- package/skills/optbrew/licenses/marketing-search.txt +21 -0
- package/skills/optbrew/licenses/mblode-seo.txt +21 -0
- package/skills/optbrew/licenses/naver-searchadvisor.txt +29 -0
- package/skills/optbrew/licenses/seranking-seo.txt +21 -0
- package/skills/optbrew/modules/firecrawl-seo-audit/GUIDE.md +64 -0
- package/skills/optbrew/modules/magnus-seo/GUIDE.md +79 -0
- package/skills/optbrew/modules/magnus-seo/README.md +45 -0
- package/skills/optbrew/modules/magnus-seo/assets/audit-report-template.md +76 -0
- package/skills/optbrew/modules/magnus-seo/references/aeo-methodology.md +105 -0
- package/skills/optbrew/modules/magnus-seo/references/agent-readable-content.md +28 -0
- package/skills/optbrew/modules/magnus-seo/references/content-and-entity-architecture.md +100 -0
- package/skills/optbrew/modules/magnus-seo/references/content-strategy-seo.md +142 -0
- package/skills/optbrew/modules/magnus-seo/references/discovery-and-freshness.md +47 -0
- package/skills/optbrew/modules/magnus-seo/references/evidence-boundaries.md +75 -0
- package/skills/optbrew/modules/magnus-seo/references/ghost-metadata.md +204 -0
- package/skills/optbrew/modules/magnus-seo/references/implementation-playbook.md +114 -0
- package/skills/optbrew/modules/magnus-seo/references/measurement-and-experimentation.md +47 -0
- package/skills/optbrew/modules/magnus-seo/references/onpage-seo.md +154 -0
- package/skills/optbrew/modules/magnus-seo/references/platform-guidance.md +30 -0
- package/skills/optbrew/modules/magnus-seo/references/schema-markup.md +244 -0
- package/skills/optbrew/modules/magnus-seo/references/source-index.md +36 -0
- package/skills/optbrew/modules/magnus-seo/references/structured-data.md +56 -0
- package/skills/optbrew/modules/magnus-seo/references/technical-seo.md +99 -0
- package/skills/optbrew/modules/magnus-seo/scripts/aeo_audit.py +158 -0
- package/skills/optbrew/modules/magnus-seo/scripts/build_prompt_matrix.py +52 -0
- package/skills/optbrew/modules/magnus-seo/templates/aeo-implementation-plan.md +53 -0
- package/skills/optbrew/modules/magnus-seo/templates/citation-observation-log.md +16 -0
- package/skills/optbrew/modules/magnus-seo/templates/llms.txt.template +15 -0
- package/skills/optbrew/modules/magnus-seo/templates/question-cluster.md +27 -0
- package/skills/optbrew/modules/magnus-seo/templates/robots-ai-crawlers.txt +23 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/GUIDE.md +483 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/agent-readiness.md +57 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/citations-vs-recommendations.md +85 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-patterns.md +287 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-types.md +71 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/format-volatility.md +98 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/okf.md +104 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/platform-ranking-factors.md +154 -0
- package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/youtube-ai-citations.md +60 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/GUIDE.md +303 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/references/event-library.md +260 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/references/ga4-implementation.md +300 -0
- package/skills/optbrew/modules/marketing-search/skills/analytics/references/gtm-implementation.md +390 -0
- package/skills/optbrew/modules/marketing-search/skills/content-strategy/GUIDE.md +432 -0
- package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/content-distribution.md +83 -0
- package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/headless-cms.md +194 -0
- package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/GUIDE.md +231 -0
- package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/references/playbooks.md +308 -0
- package/skills/optbrew/modules/marketing-search/skills/schema/GUIDE.md +172 -0
- package/skills/optbrew/modules/marketing-search/skills/schema/references/schema-examples.md +398 -0
- package/skills/optbrew/modules/marketing-search/skills/seo-audit/GUIDE.md +492 -0
- package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/ai-writing-detection.md +200 -0
- package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/international-seo.md +230 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/GUIDE.md +350 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/mermaid-templates.md +216 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/navigation-patterns.md +305 -0
- package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/site-type-templates.md +293 -0
- package/skills/optbrew/modules/mblode-seo/GUIDE.md +74 -0
- package/skills/optbrew/modules/mblode-seo/references/answer-engines.md +58 -0
- package/skills/optbrew/modules/mblode-seo/references/audit.md +78 -0
- package/skills/optbrew/modules/mblode-seo/references/brief-template.md +47 -0
- package/skills/optbrew/modules/mblode-seo/references/monitoring.md +56 -0
- package/skills/optbrew/modules/mblode-seo/references/nextjs-implementation.md +65 -0
- package/skills/optbrew/modules/mblode-seo/references/research-protocol.md +37 -0
- package/skills/optbrew/modules/mblode-seo/references/sources.md +47 -0
- package/skills/optbrew/modules/mblode-seo/references/validation-evidence.md +21 -0
- package/skills/optbrew/modules/naver-searchadvisor/GUIDE.md +75 -0
- package/skills/optbrew/modules/naver-searchadvisor/NOTICE.md +59 -0
- package/skills/optbrew/modules/naver-searchadvisor/references/INDEX.md +97 -0
- package/skills/optbrew/modules/naver-searchadvisor/scripts/audit.mjs +714 -0
- package/skills/optbrew/modules/naver-searchadvisor/scripts/robots.mjs +77 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-ai-search-share-of-voice/GUIDE.md +94 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/GUIDE.md +186 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/api-surface-map.md +207 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/auth-and-keys.md +182 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/integration-patterns.md +283 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/rate-limits-and-credits.md +235 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-competitor-gap-analysis/GUIDE.md +117 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/GUIDE.md +155 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/cite.md +84 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/core-eeat.md +147 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/templates/verdict.md +63 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/GUIDE.md +141 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/references/preflight.md +73 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-geo/GUIDE.md +159 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/GUIDE.md +393 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/cwv-audit-report.md +48 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/gsc-performance-report.md +44 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/indexation-status-report.md +43 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/auth-setup.md +160 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/cross-skill-integration.md +187 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/ga4-data-api.md +184 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/indexing-api.md +109 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/keyword-planner-api.md +66 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/nlp-api.md +55 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/pagespeed-crux-api.md +204 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/rate-limits-quotas.md +75 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/search-console-api.md +156 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/supplementary-apis.md +99 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/youtube-api.md +49 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-keyword-niche/GUIDE.md +174 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-page/GUIDE.md +174 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-plan/GUIDE.md +220 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/GUIDE.md +135 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/references/google-rich-results.md +89 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/article.json +23 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/breadcrumb-list.json +18 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/faq-page.json +22 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/local-business.json +32 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/product.json +25 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-sitemap/GUIDE.md +128 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/GUIDE.md +235 -0
- package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/references/severity-mapping.md +133 -0
- package/skills/optbrew/references/api.md +45 -0
- package/skills/optbrew/references/check-registry.json +28 -0
- package/skills/optbrew/references/evidence.md +9 -0
- package/skills/optbrew/references/intake.md +9 -0
- package/skills/optbrew/references/measurement.md +29 -0
- package/skills/optbrew/references/policies.md +7 -0
- package/skills/optbrew/references/profiles.json +13 -0
- package/skills/optbrew/references/remediations.json +12 -0
- package/skills/optbrew/references/report.md +25 -0
- package/skills/optbrew/references/routing.md +15 -0
- package/skills/optbrew/references/schemas/contract.schema.json +51 -0
- package/skills/optbrew/references/scoring.md +62 -0
- package/skills/optbrew/scripts/adapters/anthropic.mjs +116 -0
- package/skills/optbrew/scripts/adapters/imports.mjs +81 -0
- package/skills/optbrew/scripts/audit.mjs +145 -0
- package/skills/optbrew/scripts/cli.mjs +41 -0
- package/skills/optbrew/scripts/core/bootstrap.mjs +31 -0
- package/skills/optbrew/scripts/core/bundle.mjs +73 -0
- package/skills/optbrew/scripts/core/capabilities.mjs +19 -0
- package/skills/optbrew/scripts/core/collector.mjs +236 -0
- package/skills/optbrew/scripts/core/compare.mjs +47 -0
- package/skills/optbrew/scripts/core/contracts.mjs +144 -0
- package/skills/optbrew/scripts/core/cost-ledger.mjs +95 -0
- package/skills/optbrew/scripts/core/findings.mjs +54 -0
- package/skills/optbrew/scripts/core/metrics.mjs +97 -0
- package/skills/optbrew/scripts/core/protocol.mjs +125 -0
- package/skills/optbrew/scripts/core/report.mjs +652 -0
- package/skills/optbrew/scripts/core/scope.mjs +52 -0
- package/skills/optbrew/scripts/core/score.mjs +71 -0
- package/skills/optbrew/scripts/core/weights.mjs +139 -0
- package/skills/optbrew/source-lock.json +2686 -0
- package/source-lock.json +2686 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Auth & Keys
|
|
2
|
+
|
|
3
|
+
The full picture of how to authenticate against SE Ranking's APIs and the MCP server. Used by the `seo-api` skill to answer "how do I auth", "where does the key come from", "what's the OAuth flow", and "how do I run this headlessly in CI".
|
|
4
|
+
|
|
5
|
+
## Key types — single source of truth
|
|
6
|
+
|
|
7
|
+
As of 2026, **one API key authenticates everything**. The legacy split into separate Data and Project keys is gone. The same UUID-format key works against:
|
|
8
|
+
|
|
9
|
+
- All `DATA_*` MCP tools and the underlying `/v1/backlinks/*`, `/v1/domain/*`, `/v1/keywords/*`, `/v1/serp/*`, `/v1/audit/*`, `/v1/ai-search/*`, `/v1/account/*` REST endpoints.
|
|
10
|
+
- All `PROJECT_*` MCP tools and the underlying `/v1/projects/*`, `/v1/projects/{id}/keywords/*`, `/v1/projects/{id}/audits/*`, `/v1/projects/{id}/backlinks/*`, `/v1/projects/{id}/airt/*`, `/v1/account/*` REST endpoints.
|
|
11
|
+
|
|
12
|
+
Get keys at: <https://online.seranking.com/admin.api.dashboard.html>.
|
|
13
|
+
|
|
14
|
+
You can mint multiple keys per account — useful for splitting rate-limit budgets across environments (dev, staging, prod) or workloads (research vs. recurring jobs).
|
|
15
|
+
|
|
16
|
+
### Required plan
|
|
17
|
+
|
|
18
|
+
- **Data API access** ships with: any plan that has API credits — Business / Enterprise plans (100K credits/month included), API add-on (1M+), or standalone API plan (1M+).
|
|
19
|
+
- **Project API access** requires: Business or Enterprise plan. The Project API consumes plan limits ("Sites", "Keywords", "Audit Pages", "AIRT Prompts") rather than credits.
|
|
20
|
+
|
|
21
|
+
If the user is on Essential or Pro, Project API tools will return `403 Subscription required`. Surface the upgrade link: <https://seranking.com/subscription.html>.
|
|
22
|
+
|
|
23
|
+
## REST API auth
|
|
24
|
+
|
|
25
|
+
### Recommended — Authorization header
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
curl -X GET 'https://api.seranking.com/v1/account/subscription' \
|
|
29
|
+
-H 'Authorization: Token YOUR_API_KEY'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Token scheme prefix is **`Token`**, not `Bearer`.
|
|
33
|
+
|
|
34
|
+
### Fallback — query parameter
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
curl -X GET 'https://api.seranking.com/v1/account/subscription?apikey=YOUR_API_KEY'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Avoid the query param in production — it leaks the key into access logs, browser history, and HTTP referrers. Header is always preferred.
|
|
41
|
+
|
|
42
|
+
### Liveness check
|
|
43
|
+
|
|
44
|
+
The cheapest way to confirm a key is valid (0 credits):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
curl -X GET 'https://api.seranking.com/v1/account/subscription' \
|
|
48
|
+
-H 'Authorization: Token YOUR_API_KEY'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`200 OK` with a `subscription_info` payload = key is alive. `401 Unauthorized` = key is invalid or revoked.
|
|
52
|
+
|
|
53
|
+
## MCP server auth
|
|
54
|
+
|
|
55
|
+
The MCP server at `https://api.seranking.com/mcp` is the recommended interface for any agentic workflow. It supports two auth modes, **pick one per client**:
|
|
56
|
+
|
|
57
|
+
### Mode 1 — OAuth 2.1 (interactive, recommended for IDEs and desktop)
|
|
58
|
+
|
|
59
|
+
Opens a browser on first connect, stores the token locally, reuses across sessions. Right for Claude Desktop, Claude Code on a workstation, Cursor, Codex IDE.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
claude mcp add --transport http se-ranking https://api.seranking.com/mcp
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
First tool call triggers the browser sign-in. Subsequent calls reuse the refresh token (30-day sliding window, configurable via `MCP_REFRESH_TOKEN_TTL` server-side).
|
|
66
|
+
|
|
67
|
+
### Mode 2 — API key header (non-interactive, recommended for CI / headless)
|
|
68
|
+
|
|
69
|
+
Pass the key directly. Server skips OAuth entirely.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
claude mcp add --transport http se-ranking https://api.seranking.com/mcp \
|
|
73
|
+
--header "X-Api-Key: $SERANKING_API_KEY"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The header `X-Data-Api-Key` is still accepted as an alias for `X-Api-Key` (backwards compat with older self-hosted installs).
|
|
77
|
+
|
|
78
|
+
### Precedence when both are present
|
|
79
|
+
|
|
80
|
+
If a request arrives with both header auth and an `Authorization: Bearer …` token from a previous OAuth session, **headers win**. This lets you override a stale Bearer token without reconfiguring the client.
|
|
81
|
+
|
|
82
|
+
### Discovery endpoints (auto-resolved by spec-compliant clients)
|
|
83
|
+
|
|
84
|
+
| Endpoint | Purpose |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `/.well-known/oauth-authorization-server` | RFC 8414 authorization server metadata |
|
|
87
|
+
| `/.well-known/oauth-protected-resource` | RFC 9728 protected-resource metadata |
|
|
88
|
+
| `/.well-known/openid-configuration` | OIDC compatibility for clients that probe OIDC first |
|
|
89
|
+
| `/register` | RFC 7591 dynamic client registration (no manual `client_id` provisioning) |
|
|
90
|
+
|
|
91
|
+
## Per-client configuration cheat-sheet
|
|
92
|
+
|
|
93
|
+
### Claude Code
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
claude mcp add --transport http se-ranking https://api.seranking.com/mcp
|
|
97
|
+
# Then /mcp to complete OAuth.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Claude Desktop / claude.ai
|
|
101
|
+
|
|
102
|
+
`Customize` → `Connectors` → `+` → `Add custom connector`. Name: `SE Ranking`. URL: `https://api.seranking.com/mcp`.
|
|
103
|
+
|
|
104
|
+
### Codex (CLI + IDE)
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
codex mcp add se-ranking --url https://api.seranking.com/mcp
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
First-time Codex users: enable the rmcp feature in `~/.codex/config.toml`:
|
|
111
|
+
|
|
112
|
+
```toml
|
|
113
|
+
[features]
|
|
114
|
+
experimental_use_rmcp_client = true
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Cursor
|
|
118
|
+
|
|
119
|
+
`.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"mcpServers": {
|
|
124
|
+
"se-ranking": {
|
|
125
|
+
"url": "https://api.seranking.com/mcp"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### VS Code
|
|
132
|
+
|
|
133
|
+
`Cmd+P` → `MCP: Add Server` → `Command (stdio)`:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npx -y mcp-remote https://api.seranking.com/mcp
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Windsurf / Zed / Gemini CLI / others
|
|
140
|
+
|
|
141
|
+
All use the same `npx -y mcp-remote https://api.seranking.com/mcp` pattern via their respective MCP config files (`~/.codeium/windsurf/mcp_config.json`, `~/.config/zed/settings.json`, `~/.gemini/settings.json`).
|
|
142
|
+
|
|
143
|
+
## Sub-accounts on a shared workspace
|
|
144
|
+
|
|
145
|
+
If the user is a sub-account on a master SE Ranking workspace, the "Sign in with SE Ranking" OAuth path won't enumerate any tools — **API access lives with the master account**. Workaround until sub-account API keys ship:
|
|
146
|
+
|
|
147
|
+
1. Get the API key from the workspace administrator (from the API Dashboard on the master account).
|
|
148
|
+
2. In the MCP connection dialog, choose **Enter API key manually** (or use Mode 2 via `X-Api-Key` header) instead of OAuth.
|
|
149
|
+
3. Paste the master key.
|
|
150
|
+
|
|
151
|
+
## Key rotation
|
|
152
|
+
|
|
153
|
+
Rotate keys when:
|
|
154
|
+
|
|
155
|
+
- A key leaks (committed to git, posted in a Slack channel, ended up in a screenshot).
|
|
156
|
+
- An employee with access leaves.
|
|
157
|
+
- A workload moves between environments and you want clean rate-limit accounting.
|
|
158
|
+
|
|
159
|
+
Rotation:
|
|
160
|
+
|
|
161
|
+
1. Generate a new key at the API Dashboard.
|
|
162
|
+
2. Roll the new key into production (env var, secret manager).
|
|
163
|
+
3. Revoke the old key.
|
|
164
|
+
4. **Note:** keys are validated and cached server-side. After revoking, allow up to 60 seconds for the cache to invalidate before assuming the old key is fully dead.
|
|
165
|
+
|
|
166
|
+
## Common 401 / 403 patterns
|
|
167
|
+
|
|
168
|
+
| HTTP | `error.message` | What it means | Fix |
|
|
169
|
+
|---|---|---|---|
|
|
170
|
+
| 401 | `Unauthorized` | Key missing, malformed, or revoked. | Re-check `Authorization` header format. Token scheme is `Token`, not `Bearer`. |
|
|
171
|
+
| 401 | `API key provided via X-Api-Key failed validation.` | Format check passed (UUID-shaped) but liveness probe to `/v1/account/info` failed. | Key is revoked or typo'd. |
|
|
172
|
+
| 403 | `Insufficient funds` | Data API balance too low for the requested cost. | Top up at the API Dashboard, or downsize the request. |
|
|
173
|
+
| 403 | `Subscription required` | Project API call from a non-Business/Enterprise plan. | Upgrade plan, or stick to Data API only. |
|
|
174
|
+
| 403 | `Limit reached` | Project API plan limit ("Sites", "Keywords", "Audit Pages", "AIRT Prompts") exceeded. | Upgrade plan, or release unused resources via the corresponding `PROJECT_delete*` tool. |
|
|
175
|
+
|
|
176
|
+
## Storing keys safely
|
|
177
|
+
|
|
178
|
+
- **Never commit keys to git.** Even in private repos. Use `.env` (gitignored) + a secret manager (1Password, Doppler, AWS Secrets Manager, Vault).
|
|
179
|
+
- **Don't pass keys in URL query parameters.** They leak into access logs.
|
|
180
|
+
- **For client-side code:** API keys must never reach the browser. Proxy through your own backend.
|
|
181
|
+
- **For CI:** use the platform's secret store (GitHub Actions secrets, GitLab CI variables, etc.).
|
|
182
|
+
- **For Docker:** pass via `--env-file`, never bake into the image layer.
|
package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/integration-patterns.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Integration Patterns
|
|
2
|
+
|
|
3
|
+
Five canonical recipes the `seo-api` skill draws from. Each one is ready to paste — the skill adapts variable names, target domains, and credentials but doesn't need to re-derive the shape.
|
|
4
|
+
|
|
5
|
+
## Pattern 1 — Rank tracker setup (Project API)
|
|
6
|
+
|
|
7
|
+
**Goal:** stand up a new project, add a search engine, add 50 keywords, run the first position check.
|
|
8
|
+
|
|
9
|
+
**Surfaces used:** Project API.
|
|
10
|
+
**Plan cost:** 1 Site + 50 Keywords from the user's subscription.
|
|
11
|
+
**Credits:** 0 (Project API).
|
|
12
|
+
|
|
13
|
+
### MCP-tool-call sequence
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
1. PROJECT_listProjects // confirm the project doesn't already exist
|
|
17
|
+
2. PROJECT_createProject // domain="acme.com", name="ACME Rank Tracker"
|
|
18
|
+
3. PROJECT_addSearchEngine // project_id=<from #2>, country_code="us"
|
|
19
|
+
4. PROJECT_addKeywords // project_id=<from #2>, keywords=[...50 strings]
|
|
20
|
+
5. PROJECT_runPositionCheck // project_id=<from #2>
|
|
21
|
+
6. PROJECT_getPositionHistory // project_id=<from #2> (poll until ready)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Python equivalent
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import os, time, requests
|
|
28
|
+
|
|
29
|
+
API_KEY = os.environ["SERANKING_API_KEY"]
|
|
30
|
+
HEADERS = {"Authorization": f"Token {API_KEY}", "Content-Type": "application/json"}
|
|
31
|
+
BASE = "https://api.seranking.com/v1"
|
|
32
|
+
|
|
33
|
+
DOMAIN = "acme.com"
|
|
34
|
+
NAME = "ACME Rank Tracker"
|
|
35
|
+
COUNTRY = "us"
|
|
36
|
+
KEYWORDS = ["seo software", "rank tracker", ...] # 50 total
|
|
37
|
+
|
|
38
|
+
project = requests.post(f"{BASE}/projects", json={"domain": DOMAIN, "name": NAME}, headers=HEADERS).json()
|
|
39
|
+
project_id = project["id"]
|
|
40
|
+
|
|
41
|
+
requests.post(f"{BASE}/projects/{project_id}/search-engines", json={"country_code": COUNTRY}, headers=HEADERS)
|
|
42
|
+
|
|
43
|
+
requests.post(
|
|
44
|
+
f"{BASE}/projects/{project_id}/keywords",
|
|
45
|
+
json={"keywords": KEYWORDS},
|
|
46
|
+
headers=HEADERS,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
requests.post(f"{BASE}/projects/{project_id}/positions/check", headers=HEADERS)
|
|
50
|
+
|
|
51
|
+
# Position checks are async — poll
|
|
52
|
+
for _ in range(20):
|
|
53
|
+
r = requests.get(f"{BASE}/projects/{project_id}/positions/history", headers=HEADERS)
|
|
54
|
+
if r.json().get("ready"):
|
|
55
|
+
positions = r.json()
|
|
56
|
+
break
|
|
57
|
+
time.sleep(15)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### When to use
|
|
61
|
+
|
|
62
|
+
User says: "set up rank tracking for X", "create a new project for client Y", "I want to monitor positions for these keywords".
|
|
63
|
+
|
|
64
|
+
### Variants
|
|
65
|
+
|
|
66
|
+
- **Local rank tracking.** Add a region: call `PROJECT_getAvailableRegions` first, then pass `region_name` (verbatim from the response, no abbreviations) to `PROJECT_addSearchEngine`.
|
|
67
|
+
- **Multiple search engines.** Loop `PROJECT_addSearchEngine` per `country_code`. Each one is independent — rank checks run in parallel.
|
|
68
|
+
- **Tagged keyword groups.** After `PROJECT_addKeywords`, use `PROJECT_createKeywordGroup` + `PROJECT_moveKeywordsToGroup` to organise.
|
|
69
|
+
|
|
70
|
+
## Pattern 2 — Bulk backlink export to BigQuery / S3 (Data API)
|
|
71
|
+
|
|
72
|
+
**Goal:** pull every backlink for a list of 250 domains and ship the rows to BigQuery for analysis.
|
|
73
|
+
|
|
74
|
+
**Surfaces used:** Data API only.
|
|
75
|
+
**Credits:** ~75,000 (25,000 for 250 summaries + 50,000 for one full domain export; multi-domain exports scale linearly).
|
|
76
|
+
**Plan cost:** 0.
|
|
77
|
+
|
|
78
|
+
### Sequence
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
1. DATA_getCreditBalance // confirm budget
|
|
82
|
+
2. for each domain:
|
|
83
|
+
DATA_getBacklinksSummary // 100 credits / domain
|
|
84
|
+
3. DATA_exportBacklinksData // 1 credit per backlink record returned (per domain)
|
|
85
|
+
4. DATA_getBacklinksExportStatus // 0 credits / call; poll
|
|
86
|
+
5. (when ready) fetch the result URL // 0 credits
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Python skeleton
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import requests, time, json
|
|
93
|
+
from google.cloud import bigquery
|
|
94
|
+
|
|
95
|
+
DOMAINS = [...] # 250 entries
|
|
96
|
+
|
|
97
|
+
bq = bigquery.Client()
|
|
98
|
+
table = bq.dataset("seo").table("backlinks")
|
|
99
|
+
|
|
100
|
+
for domain in DOMAINS:
|
|
101
|
+
summary = client.get("/backlinks/summary", params={"target": domain}).json()
|
|
102
|
+
bq.insert_rows_json(table, [summary])
|
|
103
|
+
|
|
104
|
+
task = client.post("/backlinks/export", json={"target": domain}).json()
|
|
105
|
+
task_id = task["task_id"]
|
|
106
|
+
|
|
107
|
+
while True:
|
|
108
|
+
status = client.get(f"/backlinks/export/status", params={"task_id": task_id}).json()
|
|
109
|
+
if status["status"] == "done":
|
|
110
|
+
rows = requests.get(status["result_url"]).json()
|
|
111
|
+
bq.insert_rows_json(table, rows)
|
|
112
|
+
break
|
|
113
|
+
time.sleep(15)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
(See `references/rate-limits-and-credits.md` for the `client` wrapper — it handles 429 + 403 + throttling.)
|
|
117
|
+
|
|
118
|
+
### When to use
|
|
119
|
+
|
|
120
|
+
User says: "export all backlinks for X", "ship backlinks to {warehouse}", "I need a daily/weekly backlink delta job".
|
|
121
|
+
|
|
122
|
+
### Variants
|
|
123
|
+
|
|
124
|
+
- **Incremental (delta) export.** Use `DATA_listNewLostBacklinks` instead of full export — much cheaper for daily jobs.
|
|
125
|
+
- **Filter at request time.** Pass `min_authority`, `dofollow_only`, `anchor_contains` to reduce both data volume and credit cost.
|
|
126
|
+
- **For ref domains instead of links.** Same shape with `DATA_getBacklinksRefDomains` → `DATA_listNewLostReferringDomains`.
|
|
127
|
+
|
|
128
|
+
## Pattern 3 — Audit pipeline (Project API + Data API hybrid)
|
|
129
|
+
|
|
130
|
+
**Goal:** stand up an ongoing audit for a project, then pull the latest report into a Slack alert.
|
|
131
|
+
|
|
132
|
+
**Surfaces used:** both.
|
|
133
|
+
**Credits:** 0 (audit lives on Project API).
|
|
134
|
+
**Plan cost:** Audit Pages quota (depends on crawl scope).
|
|
135
|
+
|
|
136
|
+
### Sequence
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
1. PROJECT_listProjects // resolve project_id
|
|
140
|
+
2. PROJECT_getAuditSettings // confirm current crawl scope
|
|
141
|
+
3. PROJECT_updateAuditSettings // optional — tune scope
|
|
142
|
+
4. PROJECT_createAudit // kicks off crawl
|
|
143
|
+
5. PROJECT_getAuditStatus // poll until "completed"
|
|
144
|
+
6. PROJECT_getAuditReport // top-level summary
|
|
145
|
+
7. PROJECT_getIssuesByUrl // per-URL issue list
|
|
146
|
+
8. (optional) DATA_getDomainAuthority // contextual signal for severity ranking
|
|
147
|
+
9. Slack webhook // emit alert
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Slack-alert TS skeleton
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const project = (await client.get(`/projects/list`)).find(p => p.domain === DOMAIN);
|
|
154
|
+
|
|
155
|
+
await client.post(`/projects/${project.id}/audits/create`);
|
|
156
|
+
|
|
157
|
+
let status = "pending";
|
|
158
|
+
while (status !== "completed") {
|
|
159
|
+
await sleep(60_000);
|
|
160
|
+
status = (await client.get(`/projects/${project.id}/audits/status`)).status;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const report = await client.get(`/projects/${project.id}/audits/report`);
|
|
164
|
+
const critical = report.issues.filter(i => i.severity === "critical");
|
|
165
|
+
|
|
166
|
+
if (critical.length > 0) {
|
|
167
|
+
await fetch(SLACK_WEBHOOK, {
|
|
168
|
+
method: "POST",
|
|
169
|
+
body: JSON.stringify({
|
|
170
|
+
text: `⚠️ ${critical.length} critical SEO issues on ${DOMAIN}:\n${critical.map(i => `- ${i.title}`).join("\n")}`,
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### When to use
|
|
177
|
+
|
|
178
|
+
User says: "set up site auditing for X", "alert me when audit issues appear", "build an audit pipeline".
|
|
179
|
+
|
|
180
|
+
### Variants
|
|
181
|
+
|
|
182
|
+
- **One-off audit (no project).** Use `DATA_createStandardAudit` / `DATA_createAdvancedAudit` instead — fits when there's no Project API access or no need for ongoing tracking.
|
|
183
|
+
- **Compare against last week.** Hold the previous `audit_id`; diff `PROJECT_getAuditReport` summaries to detect new/resolved issues.
|
|
184
|
+
|
|
185
|
+
## Pattern 4 — AIRT visibility tracker (Project API)
|
|
186
|
+
|
|
187
|
+
**Goal:** track how often a brand appears in answers across ChatGPT / Gemini / Perplexity for a curated prompt set.
|
|
188
|
+
|
|
189
|
+
**Surfaces used:** Project API (with optional `DATA_getAiSearch*` for cross-domain comparison).
|
|
190
|
+
**Credits:** 0 (AIRT is plan-billed).
|
|
191
|
+
**Plan cost:** N AIRT Prompts from subscription.
|
|
192
|
+
|
|
193
|
+
### Sequence
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
1. PROJECT_listProjects // resolve project_id
|
|
197
|
+
2. PROJECT_listLlmEngines // confirm engines available
|
|
198
|
+
3. (optional) PROJECT_createLlmEngine // if a custom engine is needed
|
|
199
|
+
4. PROJECT_createPromptGroup // group the prompts logically
|
|
200
|
+
5. PROJECT_addPrompts // attach 20–50 prompts
|
|
201
|
+
6. PROJECT_getLlmStatus // poll — answers refresh on a schedule
|
|
202
|
+
7. PROJECT_getPromptAnswer (per prompt) // current top-N answers
|
|
203
|
+
8. PROJECT_getPromptsRankings // brand mention positions across the group
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### When to use
|
|
207
|
+
|
|
208
|
+
User says: "track brand mentions in LLMs", "AIRT setup", "AI Result Tracker prompts for X", "build LLM visibility dashboard".
|
|
209
|
+
|
|
210
|
+
### Variants
|
|
211
|
+
|
|
212
|
+
- **Cross-domain competitive view.** Pair with `DATA_getAiSearchLeaderboard` + `DATA_getAiSearchOverview` for a benchmark against domains you don't own.
|
|
213
|
+
- **Per-engine breakdown.** Call `PROJECT_getLlmStatistics` filtered by engine_id for an engine-by-engine heatmap.
|
|
214
|
+
|
|
215
|
+
## Pattern 5 — Keyword research bulk job (Data API)
|
|
216
|
+
|
|
217
|
+
**Goal:** for a list of seed keywords, expand each into related / similar / longtail / question keywords, write the merged result to a CSV.
|
|
218
|
+
|
|
219
|
+
**Surfaces used:** Data API only.
|
|
220
|
+
**Credits:** ~1–5 per keyword expanded (varies by tool).
|
|
221
|
+
**Plan cost:** 0.
|
|
222
|
+
|
|
223
|
+
### Sequence
|
|
224
|
+
|
|
225
|
+
```text
|
|
226
|
+
for each seed:
|
|
227
|
+
DATA_getRelatedKeywords
|
|
228
|
+
DATA_getSimilarKeywords
|
|
229
|
+
DATA_getLongTailKeywords
|
|
230
|
+
DATA_getKeywordQuestions
|
|
231
|
+
merge + dedupe
|
|
232
|
+
write to CSV
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Python skeleton
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
import csv, itertools
|
|
239
|
+
|
|
240
|
+
SEEDS = [...] # e.g., 20 seed keywords
|
|
241
|
+
COUNTRY = "us"
|
|
242
|
+
|
|
243
|
+
rows = []
|
|
244
|
+
for seed in SEEDS:
|
|
245
|
+
rel = client.get("/keywords/related", params={"keyword": seed, "source": COUNTRY}).json()
|
|
246
|
+
sim = client.get("/keywords/similar", params={"keyword": seed, "source": COUNTRY}).json()
|
|
247
|
+
long = client.get("/keywords/longtail", params={"keyword": seed, "source": COUNTRY}).json()
|
|
248
|
+
qst = client.get("/keywords/questions", params={"keyword": seed, "source": COUNTRY}).json()
|
|
249
|
+
|
|
250
|
+
for kw in itertools.chain(rel, sim, long, qst):
|
|
251
|
+
rows.append({**kw, "source_seed": seed})
|
|
252
|
+
|
|
253
|
+
# Dedupe by keyword
|
|
254
|
+
unique = {row["keyword"]: row for row in rows}.values()
|
|
255
|
+
|
|
256
|
+
with open("keywords.csv", "w", newline="") as f:
|
|
257
|
+
writer = csv.DictWriter(f, fieldnames=["keyword", "volume", "kd", "intent", "source_seed"])
|
|
258
|
+
writer.writeheader()
|
|
259
|
+
writer.writerows(unique)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### When to use
|
|
263
|
+
|
|
264
|
+
User says: "expand these seeds", "bulk keyword research", "build a keyword list for X", "I have 20 seeds, give me 2000 keywords".
|
|
265
|
+
|
|
266
|
+
### Variants
|
|
267
|
+
|
|
268
|
+
- **By intent.** Filter on `intent` in the response: keep only `informational` + `commercial` for content briefs.
|
|
269
|
+
- **By KD ceiling.** Filter `kd <= 30` for new domains to skip the impossible-to-rank keywords.
|
|
270
|
+
- **Cluster after expansion.** Pipe the merged CSV into `seo-keyword-cluster` for pillar-and-spoke structure.
|
|
271
|
+
|
|
272
|
+
## Composing patterns
|
|
273
|
+
|
|
274
|
+
Real integrations chain these. Common compositions:
|
|
275
|
+
|
|
276
|
+
| Goal | Patterns chained |
|
|
277
|
+
|---|---|
|
|
278
|
+
| "Weekly client SEO report" | Pattern 1 (one-time setup) → Pattern 3 (recurring audit) + `PROJECT_getPositionHistory` + Pattern 2 trim (delta backlinks) |
|
|
279
|
+
| "Find the highest-value new content opportunities" | Pattern 5 → `seo-keyword-cluster` → `seo-content-brief` |
|
|
280
|
+
| "AI Search competitive intelligence" | Pattern 4 → `seo-ai-search-share-of-voice` |
|
|
281
|
+
| "Outreach prospecting" | Pattern 2 (variant: ref domains) → competitor diff → outreach CSV |
|
|
282
|
+
|
|
283
|
+
When the user's goal spans more than one pattern, the `seo-api` skill writes them all as numbered sections inside `RECIPE.md` and emits separate `code/` files per language for the combined flow.
|