Advanced local evidence generators

Export scripts for billing/access evidence.

Use these only when a CSV export is not enough. Run scripts in your own environment, validate the result in the browser-only ledger, then persist approved evidence only with an explicit Import Guard action.

No native connector required

Evidence v1.0

Run these in your environment.

Do not paste service-role keys, database URLs, API keys, raw card data, or full customer exports into public tools. These scripts produce the advanced engineer handoff format behind local validation and paid imports.

CSV starter template

Small enough to try by hand.

record_type,provider,provider_customer_id,provider_subscription_id,billing_status,app_user_id,app_access_status,grants_paid_access,amount_cents,amount_basis,billing_interval,currency,updated_at
billing_state,stripe,cus_123,sub_123,past_due,,,,7900,mrr,month,usd,2026-06-21T12:00:00.000Z
app_access_state,stripe,cus_123,sub_123,,user_123,premium,true,,,,,2026-06-21T12:05:00.000Z

Prisma app-access export

Run locally against your own app database to produce app_access_state records. No database credentials are sent to RevLint.

// export-revlint-uds.ts
import { PrismaClient } from "@prisma/client";
import { writeFileSync } from "node:fs";

const prisma = new PrismaClient();
const generatedAt = new Date();

async function main() {
  const users = await prisma.user.findMany({
    select: {
      id: true,
      stripeCustomerId: true,
      stripeSubscriptionId: true,
      tier: true,
      isSubscriptionActive: true,
      updatedAt: true
    }
  });

  const records = users.map((user) => ({
    uds_version: "1.0",
    record_type: "app_access_state",
    idempotency_key: `app-user-${user.id}-${user.updatedAt.toISOString()}`,
    source_system: "prisma",
    observed_at: generatedAt.toISOString(),
    app_user_id: String(user.id),
    provider: "stripe",
    provider_customer_id: user.stripeCustomerId,
    provider_subscription_id: user.stripeSubscriptionId,
    app_access_status: user.isSubscriptionActive ? "premium" : "free",
    app_plan: user.tier,
    grants_paid_access: Boolean(user.isSubscriptionActive && user.tier !== "free"),
    requires_payment: true,
    updated_at: user.updatedAt.toISOString()
  }));

  writeFileSync("revlint-uds-app-access.json", JSON.stringify({
    uds_version: "1.0",
    export_id: `prisma-${generatedAt.toISOString()}`,
    generated_at: generatedAt.toISOString(),
    source_type: "cli",
    source_system: "prisma",
    source_label: "local_prisma_export",
    records
  }, null, 2));
}

main().finally(() => prisma.$disconnect());

Postgres billing view

Create a standardized view in a read replica or warehouse. Export the result as CSV or JSON.

create or replace view revlint_billing_state as
select
  '1.0' as uds_version,
  'billing_state' as record_type,
  'billing-' || subscription_id || '-' || updated_at as idempotency_key,
  'warehouse' as source_system,
  now() as observed_at,
  'stripe' as provider,
  customer_id as provider_customer_id,
  subscription_id as provider_subscription_id,
  status as billing_status,
  price_id as plan_id,
  plan_name as tier,
  mrr_cents as amount_cents,
  'mrr' as amount_basis,
  billing_interval,
  lower(currency) as currency,
  current_period_end,
  updated_at
from billing_subscriptions
where updated_at >= now() - interval '120 days';

Supabase app-access query

Run from SQL editor or a local script against a project export. Keep service-role keys out of RevLint.

select
  '1.0' as uds_version,
  'app_access_state' as record_type,
  'app-access-' || id || '-' || updated_at as idempotency_key,
  'supabase' as source_system,
  now() as observed_at,
  id::text as app_user_id,
  account_id::text as app_account_id,
  'workspace' as entitlement_target_type,
  account_id::text as entitlement_target_id,
  'stripe' as provider,
  stripe_customer_id as provider_customer_id,
  stripe_subscription_id as provider_subscription_id,
  case when is_premium then 'premium' else 'free' end as app_access_status,
  plan as app_plan,
  is_premium as grants_paid_access,
  true as requires_payment,
  updated_at
from public.users
where updated_at >= now() - interval '120 days';

Segment/RudderStack event

Send lifecycle evidence into /api/uds/events with an ingest token, or paste the same batch into the local validator before connecting.

{
  "uds_version": "1.0",
  "export_id": "segment-2026-06-21T12:00:00.000Z",
  "generated_at": "2026-06-21T12:00:00.000Z",
  "source_type": "webhook",
  "source_system": "segment",
  "source_label": "billing_lifecycle_destination",
  "records": [{
    "uds_version": "1.0",
    "record_type": "lifecycle_event",
    "idempotency_key": "segment-msg-123",
    "source_system": "segment",
    "event_type": "payment_failed",
    "provider": "stripe",
    "provider_customer_id": "cus_123",
    "provider_subscription_id": "sub_123",
    "occurred_at": "2026-06-21T10:00:00.000Z",
    "observed_at": "2026-06-21T10:00:02.000Z"
  }]
}