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.
Files changed (172) hide show
  1. package/.claude-plugin/marketplace.json +6 -0
  2. package/.claude-plugin/plugin.json +6 -0
  3. package/.codex-plugin/plugin.json +13 -0
  4. package/CHANGELOG.md +20 -0
  5. package/LICENSE +21 -0
  6. package/README.ko.md +73 -0
  7. package/README.md +72 -2
  8. package/THIRD_PARTY_NOTICES.md +10 -0
  9. package/bin/optbrew.mjs +4 -0
  10. package/docs/platforms.md +31 -0
  11. package/docs/release.md +14 -0
  12. package/lib/cli.mjs +103 -0
  13. package/lib/doctor.mjs +44 -0
  14. package/lib/install.mjs +158 -0
  15. package/lib/paths.mjs +30 -0
  16. package/lib/records.mjs +44 -0
  17. package/lib/transaction.mjs +205 -0
  18. package/lib/update.mjs +181 -0
  19. package/package.json +39 -4
  20. package/plugin.json +13 -0
  21. package/skills/optbrew/LICENSE +21 -0
  22. package/skills/optbrew/SKILL.md +17 -0
  23. package/skills/optbrew/THIRD_PARTY_NOTICES.md +10 -0
  24. package/skills/optbrew/agents/openai.yaml +4 -0
  25. package/skills/optbrew/bundle-manifest.json +663 -0
  26. package/skills/optbrew/licenses/firecrawl-seo-audit.txt +15 -0
  27. package/skills/optbrew/licenses/magnus-seo.txt +21 -0
  28. package/skills/optbrew/licenses/marketing-search.txt +21 -0
  29. package/skills/optbrew/licenses/mblode-seo.txt +21 -0
  30. package/skills/optbrew/licenses/naver-searchadvisor.txt +29 -0
  31. package/skills/optbrew/licenses/seranking-seo.txt +21 -0
  32. package/skills/optbrew/modules/firecrawl-seo-audit/GUIDE.md +64 -0
  33. package/skills/optbrew/modules/magnus-seo/GUIDE.md +79 -0
  34. package/skills/optbrew/modules/magnus-seo/README.md +45 -0
  35. package/skills/optbrew/modules/magnus-seo/assets/audit-report-template.md +76 -0
  36. package/skills/optbrew/modules/magnus-seo/references/aeo-methodology.md +105 -0
  37. package/skills/optbrew/modules/magnus-seo/references/agent-readable-content.md +28 -0
  38. package/skills/optbrew/modules/magnus-seo/references/content-and-entity-architecture.md +100 -0
  39. package/skills/optbrew/modules/magnus-seo/references/content-strategy-seo.md +142 -0
  40. package/skills/optbrew/modules/magnus-seo/references/discovery-and-freshness.md +47 -0
  41. package/skills/optbrew/modules/magnus-seo/references/evidence-boundaries.md +75 -0
  42. package/skills/optbrew/modules/magnus-seo/references/ghost-metadata.md +204 -0
  43. package/skills/optbrew/modules/magnus-seo/references/implementation-playbook.md +114 -0
  44. package/skills/optbrew/modules/magnus-seo/references/measurement-and-experimentation.md +47 -0
  45. package/skills/optbrew/modules/magnus-seo/references/onpage-seo.md +154 -0
  46. package/skills/optbrew/modules/magnus-seo/references/platform-guidance.md +30 -0
  47. package/skills/optbrew/modules/magnus-seo/references/schema-markup.md +244 -0
  48. package/skills/optbrew/modules/magnus-seo/references/source-index.md +36 -0
  49. package/skills/optbrew/modules/magnus-seo/references/structured-data.md +56 -0
  50. package/skills/optbrew/modules/magnus-seo/references/technical-seo.md +99 -0
  51. package/skills/optbrew/modules/magnus-seo/scripts/aeo_audit.py +158 -0
  52. package/skills/optbrew/modules/magnus-seo/scripts/build_prompt_matrix.py +52 -0
  53. package/skills/optbrew/modules/magnus-seo/templates/aeo-implementation-plan.md +53 -0
  54. package/skills/optbrew/modules/magnus-seo/templates/citation-observation-log.md +16 -0
  55. package/skills/optbrew/modules/magnus-seo/templates/llms.txt.template +15 -0
  56. package/skills/optbrew/modules/magnus-seo/templates/question-cluster.md +27 -0
  57. package/skills/optbrew/modules/magnus-seo/templates/robots-ai-crawlers.txt +23 -0
  58. package/skills/optbrew/modules/marketing-search/skills/ai-seo/GUIDE.md +483 -0
  59. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/agent-readiness.md +57 -0
  60. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/citations-vs-recommendations.md +85 -0
  61. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-patterns.md +287 -0
  62. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-types.md +71 -0
  63. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/format-volatility.md +98 -0
  64. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/okf.md +104 -0
  65. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/platform-ranking-factors.md +154 -0
  66. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/youtube-ai-citations.md +60 -0
  67. package/skills/optbrew/modules/marketing-search/skills/analytics/GUIDE.md +303 -0
  68. package/skills/optbrew/modules/marketing-search/skills/analytics/references/event-library.md +260 -0
  69. package/skills/optbrew/modules/marketing-search/skills/analytics/references/ga4-implementation.md +300 -0
  70. package/skills/optbrew/modules/marketing-search/skills/analytics/references/gtm-implementation.md +390 -0
  71. package/skills/optbrew/modules/marketing-search/skills/content-strategy/GUIDE.md +432 -0
  72. package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/content-distribution.md +83 -0
  73. package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/headless-cms.md +194 -0
  74. package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/GUIDE.md +231 -0
  75. package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/references/playbooks.md +308 -0
  76. package/skills/optbrew/modules/marketing-search/skills/schema/GUIDE.md +172 -0
  77. package/skills/optbrew/modules/marketing-search/skills/schema/references/schema-examples.md +398 -0
  78. package/skills/optbrew/modules/marketing-search/skills/seo-audit/GUIDE.md +492 -0
  79. package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/ai-writing-detection.md +200 -0
  80. package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/international-seo.md +230 -0
  81. package/skills/optbrew/modules/marketing-search/skills/site-architecture/GUIDE.md +350 -0
  82. package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/mermaid-templates.md +216 -0
  83. package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/navigation-patterns.md +305 -0
  84. package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/site-type-templates.md +293 -0
  85. package/skills/optbrew/modules/mblode-seo/GUIDE.md +74 -0
  86. package/skills/optbrew/modules/mblode-seo/references/answer-engines.md +58 -0
  87. package/skills/optbrew/modules/mblode-seo/references/audit.md +78 -0
  88. package/skills/optbrew/modules/mblode-seo/references/brief-template.md +47 -0
  89. package/skills/optbrew/modules/mblode-seo/references/monitoring.md +56 -0
  90. package/skills/optbrew/modules/mblode-seo/references/nextjs-implementation.md +65 -0
  91. package/skills/optbrew/modules/mblode-seo/references/research-protocol.md +37 -0
  92. package/skills/optbrew/modules/mblode-seo/references/sources.md +47 -0
  93. package/skills/optbrew/modules/mblode-seo/references/validation-evidence.md +21 -0
  94. package/skills/optbrew/modules/naver-searchadvisor/GUIDE.md +75 -0
  95. package/skills/optbrew/modules/naver-searchadvisor/NOTICE.md +59 -0
  96. package/skills/optbrew/modules/naver-searchadvisor/references/INDEX.md +97 -0
  97. package/skills/optbrew/modules/naver-searchadvisor/scripts/audit.mjs +714 -0
  98. package/skills/optbrew/modules/naver-searchadvisor/scripts/robots.mjs +77 -0
  99. package/skills/optbrew/modules/seranking-seo/skills/seo-ai-search-share-of-voice/GUIDE.md +94 -0
  100. package/skills/optbrew/modules/seranking-seo/skills/seo-api/GUIDE.md +186 -0
  101. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/api-surface-map.md +207 -0
  102. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/auth-and-keys.md +182 -0
  103. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/integration-patterns.md +283 -0
  104. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/rate-limits-and-credits.md +235 -0
  105. package/skills/optbrew/modules/seranking-seo/skills/seo-competitor-gap-analysis/GUIDE.md +117 -0
  106. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/GUIDE.md +155 -0
  107. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/cite.md +84 -0
  108. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/core-eeat.md +147 -0
  109. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/templates/verdict.md +63 -0
  110. package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/GUIDE.md +141 -0
  111. package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/references/preflight.md +73 -0
  112. package/skills/optbrew/modules/seranking-seo/skills/seo-geo/GUIDE.md +159 -0
  113. package/skills/optbrew/modules/seranking-seo/skills/seo-google/GUIDE.md +393 -0
  114. package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/cwv-audit-report.md +48 -0
  115. package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/gsc-performance-report.md +44 -0
  116. package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/indexation-status-report.md +43 -0
  117. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/auth-setup.md +160 -0
  118. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/cross-skill-integration.md +187 -0
  119. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/ga4-data-api.md +184 -0
  120. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/indexing-api.md +109 -0
  121. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/keyword-planner-api.md +66 -0
  122. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/nlp-api.md +55 -0
  123. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/pagespeed-crux-api.md +204 -0
  124. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/rate-limits-quotas.md +75 -0
  125. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/search-console-api.md +156 -0
  126. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/supplementary-apis.md +99 -0
  127. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/youtube-api.md +49 -0
  128. package/skills/optbrew/modules/seranking-seo/skills/seo-keyword-niche/GUIDE.md +174 -0
  129. package/skills/optbrew/modules/seranking-seo/skills/seo-page/GUIDE.md +174 -0
  130. package/skills/optbrew/modules/seranking-seo/skills/seo-plan/GUIDE.md +220 -0
  131. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/GUIDE.md +135 -0
  132. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/references/google-rich-results.md +89 -0
  133. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/article.json +23 -0
  134. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/breadcrumb-list.json +18 -0
  135. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/faq-page.json +22 -0
  136. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/local-business.json +32 -0
  137. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/product.json +25 -0
  138. package/skills/optbrew/modules/seranking-seo/skills/seo-sitemap/GUIDE.md +128 -0
  139. package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/GUIDE.md +235 -0
  140. package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/references/severity-mapping.md +133 -0
  141. package/skills/optbrew/references/api.md +45 -0
  142. package/skills/optbrew/references/check-registry.json +28 -0
  143. package/skills/optbrew/references/evidence.md +9 -0
  144. package/skills/optbrew/references/intake.md +9 -0
  145. package/skills/optbrew/references/measurement.md +29 -0
  146. package/skills/optbrew/references/policies.md +7 -0
  147. package/skills/optbrew/references/profiles.json +13 -0
  148. package/skills/optbrew/references/remediations.json +12 -0
  149. package/skills/optbrew/references/report.md +25 -0
  150. package/skills/optbrew/references/routing.md +15 -0
  151. package/skills/optbrew/references/schemas/contract.schema.json +51 -0
  152. package/skills/optbrew/references/scoring.md +62 -0
  153. package/skills/optbrew/scripts/adapters/anthropic.mjs +116 -0
  154. package/skills/optbrew/scripts/adapters/imports.mjs +81 -0
  155. package/skills/optbrew/scripts/audit.mjs +145 -0
  156. package/skills/optbrew/scripts/cli.mjs +41 -0
  157. package/skills/optbrew/scripts/core/bootstrap.mjs +31 -0
  158. package/skills/optbrew/scripts/core/bundle.mjs +73 -0
  159. package/skills/optbrew/scripts/core/capabilities.mjs +19 -0
  160. package/skills/optbrew/scripts/core/collector.mjs +236 -0
  161. package/skills/optbrew/scripts/core/compare.mjs +47 -0
  162. package/skills/optbrew/scripts/core/contracts.mjs +144 -0
  163. package/skills/optbrew/scripts/core/cost-ledger.mjs +95 -0
  164. package/skills/optbrew/scripts/core/findings.mjs +54 -0
  165. package/skills/optbrew/scripts/core/metrics.mjs +97 -0
  166. package/skills/optbrew/scripts/core/protocol.mjs +125 -0
  167. package/skills/optbrew/scripts/core/report.mjs +652 -0
  168. package/skills/optbrew/scripts/core/scope.mjs +52 -0
  169. package/skills/optbrew/scripts/core/score.mjs +71 -0
  170. package/skills/optbrew/scripts/core/weights.mjs +139 -0
  171. package/skills/optbrew/source-lock.json +2686 -0
  172. 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.
@@ -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.