Stripe Backend

Stripe billing backend: endpoint list, secrets, Sightengine AI detection, rate limits, and Bun runtime

Overview

The Stripe backend handles billing, subscription management, and AI detection proxying for verifieddit.com. It runs as a Scaleway Serverless Container built with Nix (Bun runtime).

Repository: Sanmarcsoft/verifieddit-www (path: services/stripe-backend/)

Endpoints

MethodPathDescription
POST/create-checkout-sessionCreates Stripe Checkout session for subscription
POST/create-portal-sessionCreates Stripe Customer Portal session
POST/webhookStripe webhook receiver (signature verified)
GET/subscription-statusReturns current user subscription status
POST/ai-detectProxies AI detection request to Sightengine
GET/healthHealth check endpoint

Secrets

All secrets are managed via Pulumi config (encrypted) and injected as environment variables:

SecretPass Store PathDescription
STRIPE_SECRET_KEYpass verifieddit/stripe/secret-keyStripe API secret key
STRIPE_WEBHOOK_SECRETpass verifieddit/stripe/webhook-secretStripe webhook signing secret
CLERK_SECRET_KEYpass verifieddit/clerk/secret-keyClerk backend API key
SIGHTENGINE_API_USERpass sightengine/api-userSightengine API user ID
SIGHTENGINE_API_SECRETpass sightengine/api-secretSightengine API secret

Sightengine AI Detection

The /ai-detect endpoint proxies requests to the Sightengine API for AI-generated content detection.

API Call

1
2
3
4
5
curl -X POST "https://api.sightengine.com/1.0/check.json" \
  -F "url=<image-url>" \
  -F "models=genai" \
  -F "api_user=$(pass sightengine/api-user)" \
  -F "api_secret=$(pass sightengine/api-secret)"

Rate Limits

  • Free tier: 500 operations/month
  • Enterprise API key: Higher limits (check current plan)
  • The backend should implement caching to minimize API calls
  • Consider using D1 or KV for caching detection results by image hash

Quota Monitoring

Check current usage:

1
curl "https://api.sightengine.com/1.0/account.json?api_user=$(pass sightengine/api-user)&api_secret=$(pass sightengine/api-secret)" | jq '.usage'

Build and Deploy

Pre-build (Required)

1
2
3
cd services/stripe-backend
bun install
bun run build  # Produces dist/index.js

The dist/ directory must exist before nix build because the Nix derivation copies it directly (no FOD for network access).

Build OCI Image

1
nix build .#packages.x86_64-linux.oci-image

Push and Deploy

1
2
3
4
5
6
7
SCW_SECRET=$(pass sanmarcsoft/scaleway/api-secret)

skopeo copy docker-archive:./result \
  "docker://rg.fr-par.scw.cloud/sanmarcsoft/verifieddit-stripe-backend:testing" \
  --dest-creds "nologin:${SCW_SECRET}"

cd infra && pulumi up --stack testing

Bun Runtime Notes

The service uses Bun as the runtime in the OCI image. Key considerations:

  • Bun is included via pkgs.bun in the Nix flake
  • The entrypoint uses the absolute Nix store path to Bun: ${pkgs.bun}/bin/bun
  • This avoids the /usr/bin/env bun shebang issue in Nix sandbox
  • Bun handles the ESM bundle produced by bun run build

Stripe Webhook Setup

The webhook endpoint must be registered in the Stripe Dashboard:

  1. Go to Stripe Dashboard > Developers > Webhooks
  2. Add endpoint: https://<backend-url>/webhook
  3. Select events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted
  4. Copy the webhook signing secret to pass verifieddit/stripe/webhook-secret
  5. Update Pulumi config: pulumi config set --secret stripe-webhook-secret <value>

Troubleshooting

  • “bun: not found”: Check that the entrypoint uses the Nix store path, not a shebang
  • Stripe signature verification fails: Webhook secret may be out of sync. Re-copy from Stripe Dashboard.
  • AI detection returns empty: Check Sightengine quota. Free tier may be exhausted.
  • Cold start timeout: Set minScale: 1 in Pulumi config if cold starts are causing webhook timeouts.