agentsclimarketplace

Openpay mexico

Skill ivanovishado/agent-skills/skills/openpay-mexico

Install
npx -y skills add ivanovishado/agent-skills --skill openpay-mexico

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

OpenPay payment integration for Mexican market with card, SPEI, and OXXO support. Use when integrating Mexican payment processing, adding OpenPay to Next.js/React apps, implementing SPEI/OXXO/card payments, or handling payment webhooks. Covers REST API setup (no SDK), webhook verification, and security patterns.

SKILL.md

6.4 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it

OpenPay Mexico Integration

Integrate OpenPay payment processing for Mexican market with card, SPEI, and OXXO support.

Contents

SectionPurpose
Initial SetupSDK warning, env vars, database schema
API ClientREST API wrapper (no npm package)
Security ChecklistProduction readiness
TestingSandbox test cards
ReferenceWhen to Load
api-routes.mdBuilding the payment charge endpoint
webhook-handler.mdImplementing webhooks, ngrok setup
ui-components.mdBuilding payment forms, OXXO voucher

Initial Setup

1. SDK Warning ⚠️

DO NOT install the openpay npm package. It has known security vulnerabilities and uses an outdated callback-based API.

Instead, use OpenPay's REST API directly with native fetch. This approach is:

  • More secure (no vulnerable dependencies)
  • Simpler (no promisification needed)
  • Smaller bundle size
  • Fully typed with your own interfaces

2. Environment Variables

Add to .env.local:

OPENPAY_MERCHANT_ID=your_merchant_id
OPENPAY_PRIVATE_KEY=your_private_key
OPENPAY_PUBLIC_KEY=your_public_key
OPENPAY_WEBHOOK_SECRET=your_webhook_secret
OPENPAY_SANDBOX=true  # false for production

3. Database Schema

Add payment fields to bookings table:

-- Payment tracking
ALTER TABLE bookings ADD COLUMN payment_id TEXT;
ALTER TABLE bookings ADD COLUMN payment_method TEXT CHECK (payment_method IN ('card', 'spei', 'oxxo'));

-- Store all money in cents (BIGINT) to avoid floating-point issues
ALTER TABLE bookings ADD COLUMN guest_total_cents BIGINT;
ALTER TABLE bookings ADD COLUMN platform_fee_cents BIGINT;

-- SPEI-specific fields
ALTER TABLE bookings ADD COLUMN spei_clabe TEXT;
ALTER TABLE bookings ADD COLUMN spei_reference TEXT;

-- OXXO-specific fields
ALTER TABLE bookings ADD COLUMN oxxo_barcode_url TEXT;
ALTER TABLE bookings ADD COLUMN oxxo_reference TEXT;
ALTER TABLE bookings ADD COLUMN oxxo_expires_at TIMESTAMP WITH TIME ZONE;

API Client (No SDK)

Create src/lib/openpay.ts using direct REST API calls:

// OpenPay REST API client - no external dependencies
const OPENPAY_BASE_URL =
  process.env.OPENPAY_SANDBOX === "true"
    ? "https://sandbox-api.openpay.mx/v1"
    : "https://api.openpay.mx/v1";

const MERCHANT_ID = process.env.OPENPAY_MERCHANT_ID!;
const PRIVATE_KEY = process.env.OPENPAY_PRIVATE_KEY!;

// Types
export interface OpenPayCharge {
  id: string;
  amount: number;
  status: "in_progress" | "completed" | "failed" | "charge_pending";
  method: "card" | "bank_account" | "store";
  order_id: string;
  payment_method?: {
    reference?: string;
    clabe?: string;
    barcode_url?: string;
  };
  due_date?: string;
  error_message?: string;
}

// Base API call
async function openpayRequest<T>(endpoint: string, body: object): Promise<T> {
  const auth = Buffer.from(`${PRIVATE_KEY}:`).toString("base64");

  const response = await fetch(
    `${OPENPAY_BASE_URL}/${MERCHANT_ID}${endpoint}`,
    {
      method: "POST",
      headers: {
        Authorization: `Basic ${auth}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    },
  );

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.description || "OpenPay request failed");
  }

  return response.json();
}

// Card charge (immediate confirmation)
export const createCardCharge = (
  tokenId: string,
  amountCents: number,
  description: string,
  orderId: string,
  deviceSessionId: string,
): Promise<OpenPayCharge> => {
  return openpayRequest<OpenPayCharge>("/charges", {
    method: "card",
    source_id: tokenId,
    amount: amountCents / 100,
    description,
    order_id: orderId,
    device_session_id: deviceSessionId,
    currency: "MXN",
    capture: true,
  });
};

// SPEI charge (async confirmation via webhook)
export const createSpeiCharge = (
  amountCents: number,
  description: string,
  orderId: string,
): Promise<OpenPayCharge> => {
  return openpayRequest<OpenPayCharge>("/charges", {
    method: "bank_account",
    amount: amountCents / 100,
    description,
    order_id: orderId,
    currency: "MXN",
  });
};

// OXXO charge (async confirmation via webhook)
export const createOxxoCharge = (
  amountCents: number,
  description: string,
  orderId: string,
  expirationDate: Date,
): Promise<OpenPayCharge> => {
  return openpayRequest<OpenPayCharge>("/charges", {
    method: "store",
    amount: amountCents / 100,
    description,
    order_id: orderId,
    currency: "MXN",
    due_date: expirationDate.toISOString().split("T")[0],
  });
};

Security Checklist

Before going to production, verify:

  1. ✅ Webhook signature verification enabled
  2. ✅ All money stored in cents (BIGINT)
  3. ✅ Payment verification checks booking status
  4. ✅ Payment verification checks user ownership
  5. ✅ Environment variables secured (never in client code)
  6. ✅ HTTPS enabled for webhooks
  7. ✅ Card tokenization on client side (never send raw card data to server)
  8. ✅ Device session ID included for card payments (fraud detection)

Testing

Payment Flow

  1. Card: Immediate confirmation → booking confirmed
  2. SPEI: Shows CLABE/reference → webhook confirms (seconds)
  3. OXXO: Shows barcode → webhook confirms (24-72h)

Test Cards (Sandbox)

Card NumberResult
4111 1111 1111 1111Success
4000 0000 0000 0002Insufficient funds

See OpenPay Docs for full test card list.


Related Skills

  • mexico-market - Mexican pricing psychology, fee structures, SPEI discount strategy

Gives 1 of the 12 instructions most apis services skills give in ~1.5k tokens

Counted across 424 of the 426 authors here whose files we hold, read 2026-08-06

  • use plural nouns for resource namesin 41 of 424, across 32 files
  • use cursor-based pagination for large datasetsin 35 of 424, across 20 files
  • include rate limit headers in responsesin 25 of 424, across 13 files
  • Use kebab-case for multi-word resourcesin 23 of 424, across 13 files
  • version APIs in the URL pathin 19 of 424, across 9 files
  • use semantic HTTP status codesin 18 of 424, across 8 files
  • verify webhook signatureshere, and in 18 of 424, across 11 files
  • use query parameters for filteringin 17 of 424, across 6 files
  • use async database operationsin 14 of 424, across 7 files
  • wrap successful responses in a data fieldin 13 of 424, across 3 files
  • prefix sorting parameters with a hyphen for descending orderin 13 of 424, across 3 files
  • set appropriate HTTP status codesin 13 of 424, across 6 files

Said here and by no other author read

  • call openpay rest api directly using fetch
  • store money values in cents
  • tokenize cards on the client side
  • include device session id for card payments
  • verify booking status before payment confirmation
  • verify user ownership before payment confirmation

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.