Have an AI set up smidgen for you

This document is the source of truth for coding agents (Cursor, Claude Code, Copilot, Aider, and similar) that set up and manage smidgen for a human publisher.

Read this file completely before calling any API. Do not invent endpoints. Do not skip the human signup or approval steps.

Preferred path: npx @smidgen/cli (login, init, doctor). Raw HTTP is the fallback if the CLI cannot run.

  • HTML version: https://smidgen.io/integrations/publisher-agents
  • This markdown: https://smidgen.io/integrations/publisher-agents.md
  • OpenAPI: https://smidgen.io/integrations/publisher-agents/openapi.json
  • CLI: https://smidgen.io/integrations/publisher-agents (and GitHub packages/cli)
  • Agent catalog: https://smidgen.io/.well-known/ai-catalog.json
  • LLM index: https://smidgen.io/llms.txt

Two kinds of agents (do not mix them)

1. Paying agents (x402 buyers) discover paid URLs, receive HTTP 402, pay USDC, and retry. They never create a smidgen account. Guide: https://smidgen.io/integrations/agents 2. Publisher coding agents (you) help a human ship a paywall on their site. The human owns the account. You hold a delegated token after they approve you.

If you were asked to *pay* for content, stop and use https://smidgen.io/integrations/agents instead.

What you must never do

  • Do not create a smidgen account. There is no signup API.
  • Do not ask the human to paste a magic-link URL or session cookie into chat.
  • Do not commit smid_ag_ or smid_sk_ tokens to git. Put them in ignored env files.
  • Do not change payout wallets on an existing project. The API rejects that. The human updates payouts in the dashboard.
  • Do not use a Publisher API key (smid_sk_) as an agent token. Those keys only sync WordPress rules for one project.
  • Do not log tokens.

Step 0 — Human creates the account

Tell the human (call them George):

1. Open https://smidgen.io/login 2. Sign in with email (magic link) or a wallet (MetaMask on Base, or Phantom on Solana) 3. Confirm they can see https://smidgen.io/dashboard 4. Come back to you when that is done

Wait. Do not continue until George says he is signed in.

Free plan: 1 project, 5 paywall rules, one chain (Base or Solana). Plan limits return HTTP 403 with code PROJECT_LIMIT, RULE_LIMIT, or CHAIN_LIMIT.

Preferred — CLI (do this unless it cannot run)

npx @smidgen/cli login
npx @smidgen/cli init --name "George blog" --site https://example.com --evm-wallet 0xGeorgeBaseAddress --path "/premium/*" --stack next
npx @smidgen/cli doctor --url https://example.com/premium

From the smidgen git repo before the package is on npm:

npm run smidgen -- login
npm run smidgen -- init --name "George blog" --site https://example.com --evm-wallet 0xGeorgeBaseAddress --stack next

login runs RFC 8628 device authorization: it prints a URL + user code, George clicks Authorize, the token is stored in ~/.smidgen/credentials.json (not git). init creates the project and a paywall rule, writes .env.local (gitignored), and for --stack next writes middleware.ts if missing. doctor GETs George's URL as a bot and expects HTTP 402.

Ask George for the site URL and the payout wallet before init. Stacks: next (default), html, wordpress (mints smid_sk_ into .env.local).

If npx @smidgen/cli is not published yet, use npm run smidgen from this repo or the curl fallback below.

Fallback — device authorization (RFC 8628)

George approves you in the browser. He never pastes a secret into chat.

1a. Request a device code

curl -sS -X POST https://smidgen.io/api/v1/agent/device/code \
  -H "Content-Type: application/json" \
  -d '{"client_name":"Cursor"}'

Example response:

{
  "device_code": "high-entropy-secret-for-you-only",
  "user_code": "WDJB-MJHT",
  "verification_uri": "https://smidgen.io/device",
  "verification_uri_complete": "https://smidgen.io/device?user_code=WDJB-MJHT",
  "expires_in": 900,
  "interval": 5
}

Keep device_code secret (it is not the user code). Show George verification_uri_complete and the user_code.

Codes expire in 15 minutes. Poll no faster than interval seconds or you get slow_down.

1b. George approves

Tell George, verbatim:

> Open this URL while signed into smidgen, confirm the code matches USER_CODE, and click Authorize this agent: VERIFICATION_URI_COMPLETE

If he is not signed in, the page sends him to login and returns to /device.

1c. Poll for the access token

curl -sS -X POST https://smidgen.io/api/v1/agent/device/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=DEVICE_CODE"

JSON is also accepted: {"grant_type":"urn:ietf:params:oauth:grant-type:device_code","device_code":"DEVICE_CODE"}.

Poll every interval seconds until one of:

HTTP`error`Meaning
400authorization_pendingGeorge has not approved yet. Keep polling.
400slow_downYou polled too fast. Wait longer, then continue.
400expired_tokenStart again from 1a.
400access_deniedGeorge clicked deny. Stop.
400invalid_grantBad or already-used device_code.
200(none)Success. Save access_token.

Success body:

{
  "access_token": "smid_ag_…",
  "token_type": "Bearer",
  "expires_in": 7776000,
  "scope": "projects:read projects:write rules:write keys:write"
}

Store access_token as SMIDGEN_AGENT_TOKEN in a local env file that is gitignored. The token is shown once. Default lifetime is 90 days. George can revoke it at https://smidgen.io/dashboard/settings.

Alternative: dashboard token

If George prefers, he can open https://smidgen.io/dashboard/settings → Connect an agent → generate a token → paste smid_ag_ into your env. Same API after that. Prefer device flow so the secret never sits in the chat.

Step 2 — Confirm the token

curl -sS https://smidgen.io/api/v1/agent/me \
  -H "Authorization: Bearer smid_ag_…"

Expect user.plan and token.scopes. If 401, the token is wrong, expired, or revoked.

Step 3 — Create a project

You may set the payout wallet only when creating the project. Ask George for the address USDC should go to (MetaMask 0x… on Base, and/or Phantom on Solana). You cannot change it later via this API.

curl -sS -X POST https://smidgen.io/api/v1/agent/projects \
  -H "Authorization: Bearer smid_ag_…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "George blog",
    "siteUrl": "https://example.com",
    "evmEnabled": true,
    "evmWallet": "0xGeorgeBaseAddress",
    "evmNetwork": "eip155:8453"
  }'

Solana instead (or in addition on Pro/Business):

{
  "name": "George blog",
  "siteUrl": "https://example.com",
  "solanaEnabled": true,
  "solanaWallet": "GeorgeSolanaBase58Address",
  "solanaNetwork": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
}

Common networks:

  • Base mainnet: eip155:8453
  • Base Sepolia: eip155:84532
  • Solana mainnet: solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
  • Solana devnet: solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1

Response project.id is the public id (smid_…). Use that in every later path. It is not a secret.

List projects: GET https://smidgen.io/api/v1/agent/projects

Update name, site URLs, or default price (not payouts):

curl -sS -X PATCH https://smidgen.io/api/v1/agent/projects/smid_PROJECT \
  -H "Authorization: Bearer smid_ag_…" \
  -H "Content-Type: application/json" \
  -d '{"siteUrl":"https://example.com\nhttps://www.example.com","defaultPriceCents":10}'

defaultPriceCents is USDC cents (10 = $0.10).

Step 4 — Paywall rules

curl -sS -X PUT https://smidgen.io/api/v1/agent/projects/smid_PROJECT/rules \
  -H "Authorization: Bearer smid_ag_…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Premium article",
    "pathPattern": "/premium/*",
    "selector": "premium-article",
    "selectorType": "data-attribute",
    "priceCents": 10,
    "enabled": true,
    "origin": "https://example.com"
  }'

selectorType is data-attribute, class, or css-selector. For the HTML snippet, mark content with data-x402-paywall="premium-article" matching selector.

List: GET https://smidgen.io/api/v1/agent/projects/smid_PROJECT/rules Delete: DELETE https://smidgen.io/api/v1/agent/projects/smid_PROJECT/rules/RULE_UUID

Then install the matching publisher integration so the publisher origin returns HTTP 402 (not smidgen.io): https://smidgen.io/integrations

Step 5 — WordPress Publisher API key (optional)

WordPress uses a different key (smid_sk_), bound to one project:

curl -sS -X POST https://smidgen.io/api/v1/agent/projects/smid_PROJECT/publisher-key \
  -H "Authorization: Bearer smid_ag_…"

Shown once. Paste into WordPress → Settings → smidgen.io with API URL https://smidgen.io and the project id. Then enable Paywall this content on posts (rules sync; you usually do not PUT rules by hand).

Scopes

Default device-flow tokens include:

  • projects:read — List and read your projects
  • projects:write — Create projects and update site URLs / default price (not payout wallets after create)
  • rules:write — Create, update, and delete paywall rules
  • keys:write — Mint or rotate the WordPress Publisher API key (smid_sk_…)

There is no payouts:write scope. After create, payout changes are dashboard-only.

Security model (why this is safe)

  • Identity: George proves email or wallet at signup. You cannot mint users.
  • Delegation: RFC 8628 device grant. George sees the user code and scopes before authorize.
  • Storage: tokens hashed SHA-256 at rest; raw value shown once; prefix only in the dashboard.
  • Least privilege: no payout mutation, no billing, no account delete.
  • Revocation: https://smidgen.io/dashboard/settings
  • Rate limits on device code, polling, and API calls.
  • smid_ag_ (you) vs smid_sk_ (WordPress) vs smid_ (public project id).

After setup

  • Humans pay in the browser; bots pay via x402 on George's domain. Paying-agent snippets: https://smidgen.io/integrations/agents
  • Catalog from rules: /.well-known/ai-catalog.json on George's site. Hub catalog: https://smidgen.io/.well-known/ai-catalog.json
  • Coinbase Bazaar can list a URL after the first successful settle.

If anything 401s, stop and have George revoke + re-approve. If 403 with a plan code, explain the Free-plan cap and the pricing page https://smidgen.io/pricing.