← Back to DocsExternal Integration

Integrating PaywallOS from Your App

A complete guide to connecting your external application to PaywallOS. All endpoints support CORS for browser-based calls.

Overview

PaywallOS exposes a REST API at https://paywallos.openverb.org. You need:

  • API Key — Public key from your app (Dashboard → Apps → API Keys)
  • App ID — UUID of your app (same place)

All endpoints (except health) require: Authorization: Bearer YOUR_API_KEY

1. Health Check

GET/api/openverb/health
Verify connectivity before making real requests. No auth required.

Request

fetch('https://paywallos.openverb.org/api/openverb/health')

Response 200

{
  "status": "ok",
  "message": "PaywallOS Service is active"
}

2. Check Verb Permission (Simple)

GET/api/openverb/check-verb
REST-style check with query params. Use this if you prefer GET over POST.

Query Parameters

  • appId — Your app UUID
  • userId — Your user's unique ID
  • verb — The action (e.g. export_data)
  • tier — User's tier slug (e.g. free, pro), not the tier UUID. Optional, defaults to free.
fetch(
  'https://paywallos.openverb.org/api/openverb/check-verb?appId=YOUR_APP_ID&userId=user_123&verb=export_data&tier=free',
  { headers: { Authorization: 'Bearer YOUR_API_KEY' } }
)

Response 200 (allowed)

{
  "allowed": true,
  "verb": "export_data",
  "tier": "pro",
  "message": "Access granted"
}

Response 403 (denied)

{
  "allowed": false,
  "verb": "export_data",
  "tier": "free",
  "requiredTier": "pro",
  "message": "This feature requires the pro plan"
}

3. Check Verb Permission (POST)

POST/api/openverb/check
Used by the PaywallOS SDK. OpenVerb runtime format with full receipt.

Request Body

{
  "verbId": "export_data",
  "actor": { "type": "user", "id": "user_123" },
  "context": { "tenantId": "YOUR_APP_ID", "planId": "pro" }
}

tenantId = App ID. planId = user's tier slug.

Response 200 (allowed)

{
  "ok": true,
  "receipt": {
    "executionId": "...",
    "verbId": "export_data",
    "status": "ok",
    "actorId": "user_123",
    "tenantId": "YOUR_APP_ID"
  }
}

Response 200 (denied)

{
  "denied": true,
  "reason": {
    "code": "tier_required",
    "message": "Upgrade to Pro"
  },
  "upsell": {
    "suggestedPlanId": "pro",
    "cta": "Upgrade Now"
  }
}

4. Stripe Checkout (Upgrade)

POST/api/stripe/checkout
Create a Stripe Checkout session. Redirect the user to upgrade to Pro.

Request

fetch('https://paywallos.openverb.org/api/stripe/checkout', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    appId: 'YOUR_APP_ID',
    planId: 'tier-uuid',  // Tier UUID from dashboard, not slug
    userId: 'user_123',
    successUrl: 'https://yourapp.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancelUrl: 'https://yourapp.com/plans'
  })
})

Response

{ "url": "https://checkout.stripe.com/...", "sessionId": "cs_..." }

Redirect the user to url. Include {CHECKOUT_SESSION_ID} in successUrl so you can poll for tier updates after checkout.

5. Billing Portal (Cancel / Manage)

POST/api/stripe/customer-portal
Get a Stripe Customer Portal URL so users can cancel, update payment, or view invoices.

Request

fetch('https://paywallos.openverb.org/api/stripe/customer-portal', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    appId: 'YOUR_APP_ID',
    userId: 'user_123',
    returnUrl: 'https://yourapp.com/account'
  })
})

Response

{ "url": "https://billing.stripe.com/..." }

Redirect the user to url. Stripe hosts the portal—users can cancel at period end, update payment, view invoices.

6. Fetch User Tier

GET/api/openverb/user-tier
Get the user's tier from PaywallOS (subscription database). Use when you don't manage tiers yourself.

Query Parameters

  • appId — Your app UUID
  • userId — Your user's external ID (must exist as end_user in PaywallOS)
fetch(
  'https://paywallos.openverb.org/api/openverb/user-tier?appId=YOUR_APP_ID&userId=user_123',
  { headers: { Authorization: 'Bearer YOUR_API_KEY' } }
)

Response 200

{
  "userId": "user_123",
  "tier": "pro"
}

Returns tier: "free" if user has no active subscription.

CORS

All OpenVerb API endpoints support CORS for browser-based requests:

  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Headers: Authorization, Content-Type

You can call these endpoints directly from your frontend (e.g. fetch from React). Keep your API key in an env var (e.g. NEXT_PUBLIC_PAYWALLOS_API_KEY). The public key is safe for client-side use.

Typical Integration Flow

  1. On app load: Call /api/openverb/health to verify connectivity (optional)
  2. When user logs in: Call /api/openverb/user-tier to get their tier, or use your own tier if you manage it
  3. Initialize PaywallOS SDK with initPaywallOS(apiKey, appId, userId, userTier, { baseUrl: 'https://paywallos.openverb.org' })
  4. Add verb="export_data" to buttons/sections that need protection
  5. Or call /api/openverb/check-verb directly for programmatic checks
  6. Upgrade: Call /api/stripe/checkout → redirect to url. Use {CHECKOUT_SESSION_ID} in successUrl.
  7. Post-checkout: Poll /api/openverb/user-tier every 2–3s until tier is pro (webhooks can delay a few seconds)
  8. Cancel/Manage: For Pro users, call /api/stripe/customer-portal → redirect to url

Stripe Webhook Setup (PaywallOS)

PaywallOS receives Stripe webhooks to keep subscriptions in sync. If you run PaywallOS, configure:

  • URL: https://paywallos.openverb.org/api/stripe/webhooks (note: webhooks plural)
  • Events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_succeeded, invoice.payment_failed
  • Env: STRIPE_WEBHOOK_SECRET in Vercel

If user-tier returns free after checkout, the webhook may not be configured. Run migration 07-subscriptions-plan-id-flexible.sql if needed.

PaywallOS Sandbox

The OpenVerb JSON library defines what actions exist in the app.

Analytics
dashboard.view
Access to the main analytics dashboard and basic metrics.
data.export
Export reports and raw data to CSV or PDF formats.
data.streaming
Access to real-time websocket data and live feed updates.
AI
ai.insights
Generate automated summaries and trend detection from datasets.
ai.forecast
Access to predictive modeling and future trend forecasting.
Collaborate
team.collaboration
Shared workspaces, comments, and team-based tagging.
Developer
api.custom_keys
Generate and manage programmatic API keys for data integration.
Service
support.priority
Priority ticket handling and 24/7 technical support access.
8 verbs loaded from openverb.core.json

Subscription tiers determine pricing. Each tier unlocks specific verbs.

Free
Free
dashboard.view
1 verb included
Pro
$29/mo
dashboard.view
data.export
ai.insights
3 verbs included
Business
$99/mo
dashboard.view
data.export
data.streaming
ai.insights
ai.forecast
team.collaboration
api.custom_keys
support.priority
8 verbs included

The access control matrix. Which verbs are allowed on which tiers.

VerbFreeProBusiness
dashboard.view
data.export
50/monthly
data.streaming
ai.insights
20/monthly
ai.forecast
team.collaboration
api.custom_keys
support.priority
Active User
Try an Action