Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@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.

About

A Convex component for Payer checkout sessions and signed webhooks

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages