npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fazofazaal/convex-payer

v0.1.0

Published

A Convex component for Payer checkout sessions and webhooks.

Readme

@fazofazaal/convex-payer

A Convex component for Payer checkout sessions and signed webhooks. It stores a normalized checkout ledger in an isolated component, provides a typed server client, and lets the host app keep authentication and fulfillment in its own Convex functions.

The package starts at 0.0.1. Until 1.0.0, minor releases may refine the public API; Changesets records every release and generates the changelog.

Features

  • Create, retrieve, and cancel hosted checkout sessions.
  • Send required idempotency keys for every mutating request.
  • Store sessions by Payer ID and merchant reference.
  • Verify Payer-Signature over the exact raw webhook body.
  • Normalize documented checkout fields while ignoring unknown additive webhook properties.
  • Reject stale deliveries and accept multiple v1 signatures during rotation.
  • De-duplicate webhook events while retrying failed host-app callbacks.
  • Keep API and webhook secrets inside Convex environment variables.

Installation

pnpm add @fazofazaal/convex-payer

Mount the component:

// convex/convex.config.ts
import payer from "@fazofazaal/convex-payer/convex.config.js";
import { defineApp } from "convex/server";

const app = defineApp();
app.use(payer);
export default app;

Set secrets independently for each Convex deployment:

pnpm exec convex env set PAYER_SECRET_KEY sk_test_...
pnpm exec convex env set PAYER_WEBHOOK_SECRET whsec_...

Checkout

Create app-owned actions that authenticate the caller before using the client:

// convex/payments.ts
"use node";

import { Payer } from "@fazofazaal/convex-payer";
import { v } from "convex/values";
import { components } from "./_generated/api";
import { action } from "./_generated/server";

const payer = new Payer(components.convexPayer);

export const createCheckout = action({
  args: {
    amountLaari: v.number(),
    reference: v.string(),
    returnUrl: v.string(),
  },
  returns: v.object({ id: v.string(), url: v.string() }),
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new Error("Not authenticated");

    const session = await payer.createCheckoutSession(ctx, {
      amount: args.amountLaari,
      title: `Order ${args.reference}`,
      reference: args.reference,
      idempotencyKey: args.reference,
      returnUrl: args.returnUrl,
    });

    if (!session.url) throw new Error("Payer did not return a checkout URL");
    return { id: session.id, url: session.url };
  },
});

REST amounts are integers in laari: 100 laari equals MVR 1.

Webhooks

Register the route in the host app so application-specific fulfillment remains under the app's control:

// convex/http.ts
import { registerRoutes } from "@fazofazaal/convex-payer";
import { httpRouter } from "convex/server";
import { components, internal } from "./_generated/api";

const http = httpRouter();

registerRoutes(http, components.convexPayer, {
  webhookPath: "/api/webhooks/payer",
  onEvent: async (ctx, event) => {
    await ctx.runMutation(internal.payments.applyPayerEvent, { event });
  },
});

export default http;

Configure that HTTPS URL on Payer's Developers page and subscribe to checkout lifecycle events. The route verifies the signature before parsing JSON, records the event, invokes the callback, and returns a non-2xx response when processing must be retried.

Development

pnpm install
pnpm run build:codegen
pnpm run test
pnpm run lint
pnpm run typecheck

Add a Changeset for every user-visible change:

pnpm changeset

Releases are managed by the Changesets GitHub Action. 1.0.0 is reserved for a deliberately stable public API.

Scope

The initial component covers Payer Checkout only. QR codes, payment links, personal tokens, OAuth, payouts, and refunds are intentionally out of scope.

Found a bug or have a feature request? Open an issue at fazofazaal/convex-payer.