Shipseo API & packages
Public REST API for the workspace-scoped Pro plan, plus quickstarts for the three npm packages. Everything is curl-first, no proprietary SDK required.
Contenido
Quickstart
Get an API key from your dashboard at /team → API keys. Then your first call:
curl https://shipseo.dev/api/v1/sites \
-H "Authorization: Bearer sk_live_..."bashResponse is JSON: { sites: [...] }. All responses are UTF-8 JSON, always. Errors follow the shape { error, message, ... } — see Error codes.
Authentication
Every request to /api/v1/* must carry an Authorization: Bearer sk_live_... header. Keys are workspace-scoped — one key = one workspace.
Keys are hashed with SHA-256 in the database — the plaintext is shown once at creation. If you lose it, revoke and mint a new one from the dashboard.
Rate limits
Hourly rolling window per key. When you hit the ceiling you get a 429 with a Retry-After header (seconds).
| Plan | Requests / hour | Notes |
|---|---|---|
| FREE / STARTER | 0 | API not included |
| PRO | 100 | ~72k/mo steady state |
| AGENCY | 500 | ~360k/mo steady state |
| ENTERPRISE | unlimited | Contact us |
POST /audits also consumes your workspace's monthly audit budget (auditsPerMonth) — PRO gets 4/mo, AGENCY gets 30/mo. A curl loop can't burn the whole month's budget in seconds.
Endpoints
Three endpoints today. More coming as we validate what real integrations need.
List all sites in the caller's workspace.
curl https://shipseo.dev/api/v1/sites \
-H "Authorization: Bearer sk_live_..."bashResponse:
{
"sites": [
{
"id": "site_cmt61a2340004o98zuxl8xitc",
"name": "Acme Marketing",
"url": "https://acme.com",
"domain": "acme.com",
"createdAt": "2026-08-01T00:00:00.000Z"
}
]
}jsonTrigger a full-site audit on one of your sites. Synchronous — waits for the audit to complete (~10-30s typical) before responding.
curl -X POST https://shipseo.dev/api/v1/audits \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"siteId":"site_cmt61a2340004o98zuxl8xitc"}'bashResponse (200):
{
"auditId": "audit_cmt6bkcho0001pockb25ef4hv",
"score": 82,
"issueCount": 6,
"pagesCrawled": 15,
"durationMs": 12500
}jsonConsumes 1 from your monthly auditsPerMonth budget. Returns 403 plan_limit when the cap is hit.
Fetch a single audit and its detected issues.
curl https://shipseo.dev/api/v1/audits/audit_... \
-H "Authorization: Bearer sk_live_..."bashResponse (200):
{
"audit": {
"id": "audit_...",
"status": "COMPLETED",
"score": 82,
"startedAt": "2026-08-23T21:00:00.000Z",
"completedAt": "2026-08-23T21:00:12.500Z",
"site": {
"id": "site_...",
"name": "Acme Marketing",
"url": "https://acme.com"
},
"issues": [
{
"id": "issue_...",
"category": "meta",
"type": "missing_meta_description",
"severity": "HIGH",
"title": "Falta meta description",
"description": "Sin meta description...",
"affectedUrl": null,
"affectedUrls": ["https://acme.com/pricing"],
"value": null,
"recommended": "Meta description única de 120-160 caracteres"
}
]
}
}jsonReturns 404 audit_not_found if the audit doesn't belong to your workspace — same response as a real unknown id, so cross-tenant existence isn't leaked.
Error codes
All errors follow the shape { error: "<slug>", message: "<human>" }. Slugs are stable — branch on error, display message.
| HTTP | error slug | When |
|---|---|---|
| 400 | invalid_json | Body was not valid JSON |
| 400 | missing_site_id | POST /audits without siteId |
| 401 | missing_auth | No Authorization header |
| 401 | unauthorized | Key unknown, revoked, expired, or plan downgraded |
| 403 | plan_not_included | Workspace plan doesn't include the API |
| 403 | plan_limit | Monthly quota reached (e.g. audits/mo) |
| 404 | site_not_found | Site doesn't exist or belongs to another workspace |
| 404 | audit_not_found | Same, for audits |
| 429 | rate_limited | Hourly cap hit — respect Retry-After |
| 502 | audit_failed | Target site crawl failed (DNS, timeout, 5xx) |
Admin API
Cross-tenant REST for platform admins. Distinct from the workspace-scoped v1 API above — this one uses sk_admin_* keys and can read/write across every workspace. All calls are logged to AdminApiCallLog.
These endpoints require an sk_admin_* key, which only a PlatformAdmin user can create. There is no UI for creating one — a real admin runs the mint script server-side:
pnpm --filter @shipseo/web exec tsx scripts/create-admin-api-key.ts \
--email admin@yourcompany.com --label "support-ops"bashAlso available: generic tRPC dispatcher at POST /api/admin/trpc/<namespace>.<procedure> for anything not wrapped in v1 yet.
Platform metrics: workspace counts by status, plan distribution, activity, cost roll-ups over the last 30d.
curl https://shipseo.dev/api/admin/v1/overview \
-H "Authorization: Bearer sk_admin_..."bashCross-tenant workspace list with search + filters + pagination.
curl "https://shipseo.dev/api/admin/v1/workspaces?plan=PRO&status=ACTIVE&page=0&pageSize=25" \
-H "Authorization: Bearer sk_admin_..."bashQuery params: search (name/slug/owner email), plan, status, page, pageSize (max 100).
Full workspace detail: billing, members, sites, integration health.
curl https://shipseo.dev/api/admin/v1/workspaces/cmt61a2340001o98zmlvj9cv0 \
-H "Authorization: Bearer sk_admin_..."bashUnified update. Include any combination of plan, status, trialEndsAt plus a required reason (≥5 chars, logged for the audit trail).
curl -X PATCH https://shipseo.dev/api/admin/v1/workspaces/cmt61a234... \
-H "Authorization: Bearer sk_admin_..." \
-H "Content-Type: application/json" \
-d '{
"plan": "PRO",
"status": "ACTIVE",
"reason": "manual upgrade after PayPal reconciliation"
}'bashFields apply sequentially. If one fails and others succeed, the response is 207 Multi-Status with a { applied: [{ field, ok, error? }] } array so you know exactly what landed.
Cross-tenant audit trail. Every plan override / status flip / trial extension is captured with the acting admin + reason.
curl "https://shipseo.dev/api/admin/v1/action-log?targetId=cmt61a234...&pageSize=50" \
-H "Authorization: Bearer sk_admin_..."bashQuery params: adminUserId, action (workspace.update_plan | workspace.set_status | workspace.extend_trial),targetId, page, pageSize.
Packages
Three MIT-licensed dev-facing packages, all installable without a Shipseo account. Point of entry depends on what you're building.
MCP server for Cursor / Claude Desktop / VS Code (Copilot Chat) / Windsurf. Your editor's LLM audits, tracks history, and lists pending fixes without leaving the IDE.
// ~/.cursor/mcp.json · claude_desktop_config.json
// .vscode/mcp.json (VS Code + Copilot Chat)
{
"mcpServers": {
"shipseo": {
"command": "npx",
"args": ["-y", "@shipseo/mcp"]
}
}
}jsonNext.js SDK. Resolves per-route SEO metadata from the dashboard at render time, with a local fallback so a Shipseo outage never breaks your <head>.
// app/layout.tsx
import { shipseoMetadata } from '@shipseo/next';
export async function generateMetadata() {
return shipseoMetadata({
route: '/',
fallback: { title: 'My app' },
});
}tsxOne-shot scaffolder. Detects Next.js App/Pages Router and writes sitemap.ts, robots.ts, and metadata boilerplate — with backup if files existed.
# In your Next.js project
npx @shipseo/initbashEverything above — the API code, the packages, the docs page itself — is in the same monorepo, MIT licensed. File an issue or PR if something's off.