Skip to main content

End-to-end checklist

Run through every item. Don't ship until each one passes.

Catalog visibility

  • GET /agents/by-slug/<slug> returns 200 with full DTO.
  • Marketplace homepage shows the agent (if featured: true) or browse grid shows it (if not).
  • Detail page /agent/<slug> renders without console errors.
  • Capabilities, steps, changelog, photos all appear.
  • Tag/category color theme looks correct.
  • Mobile viewport (375px) renders cleanly.

Pricing

  • All pricing tiers show on the detail page.
  • Recommended tier is visually highlighted.
  • Free tier "Get started" goes to dashboard subscription without Stripe.
  • Paid tier "Subscribe" redirects to Stripe Checkout.
  • On successful checkout, you land back at returnUrl (or /dashboard if none).
  • Dashboard /dashboard shows the new subscription with status: 'active'.

OAuth (Track A)

  • Visiting the agent's frontend redirects unauthenticated users to the marketplace login.
  • After login + consent, the user is redirected back with a session cookie set on the agent backend.
  • GET <agent>/me returns { id, email, name, marketplaceRole }.
  • Signing out on the marketplace does not automatically sign the user out of the agent (separate sessions — expected).
  • Refresh tokens work: leave the session idle for >10 hours, return, no re-login needed.

Subscription resolution

  • Agent backend can call GET /me/subscriptions/<agentId> server-to-server with Authorization: Bearer <access_token>.
  • An unsubscribed user receives 404.
  • A subscribed user receives the full subscription DTO including the embedded tier.
  • After upgrading on the marketplace, the agent reflects the new tier within one token refresh cycle (or sooner if the agent doesn't cache the hint).

Quota arithmetic

  • Define one metric of each kind (fixed + rolling) for testing.
  • On the free tier, consume returns 200 until quota is hit, then 429 with error.code === "QUOTA_EXCEEDED" and error.details.remaining === 0.
  • On the paid tier, the consume cap matches the tier's quotaLimit.
  • release on a fixed metric decrements used and is reflected in GET /me/agents/:agentId/usage/<slug>.
  • release on a rolling metric returns 422.
  • Same clientReqId used twice on consume doesn't double-charge.
  • A 0-quota gate (boolean feature) correctly blocks the agent's UI for that tier.

Stripe lifecycle

  • checkout.session.completed webhook fires → user_agent_subscriptions row is upserted with status: 'active'.
  • customer.subscription.updated (after a plan change) updates the local row.
  • customer.subscription.deleted flips status to canceled.
  • invoice.payment_failed flips status to past_due.
  • All events appear in stripe_events with processedAt set.
  • Reprocessing the same event ID is a no-op (idempotency).

Admin

  • /admin/agents lists the agent.
  • Edit form persists updates.
  • /admin/interactions shows a row for each demo request, signup, waitlist hit, subscription creation.
  • Adding a notification recipient via /admin/interactions/recipients actually receives emails on next interaction.

RBAC

  • An org_member cannot call any of the admin endpoints (/admin/*, agent CRUD, tier CRUD) — receives 403 with error.code === "FORBIDDEN".
  • An org_admin cannot create or edit agents — receives 403.
  • A platform_admin can do all of the above.

Audit log

  • POSTHOG_API_KEY is set in production. Requests appear in the PostHog project within ~30s (the batch interval).
  • Failed requests log a row with result: 'failure' and an errorCode.

Security

  • OAuth redirectUris allow-list contains only legitimate origins.
  • FRONTEND_URL env var on the backend matches the actual marketplace UI origin.
  • Stripe webhook signature verification is succeeding (no 400s in webhook logs).
  • Cookies are HttpOnly, Secure, SameSite=None in production.
  • No secrets are leaked in audit log entries.

Coming-soon mode (optional)

If launching as coming_soon:

  • Agent card renders the "Coming soon" badge.
  • Click opens the NotifyDialog.
  • Email submit creates an agent_waitlist row and an interactions row with type: 'notify_request'.
  • Notification recipients receive an email.

Done

When every checkbox passes, move on to Publishing & approval.