Openpay mexico
npx -y skills add ivanovishado/agent-skills --skill openpay-mexicoAssembled 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
| Section | Purpose |
|---|---|
| Initial Setup | SDK warning, env vars, database schema |
| API Client | REST API wrapper (no npm package) |
| Security Checklist | Production readiness |
| Testing | Sandbox test cards |
| Reference | When to Load |
|---|---|
| api-routes.md | Building the payment charge endpoint |
| webhook-handler.md | Implementing webhooks, ngrok setup |
| ui-components.md | Building payment forms, OXXO voucher |
Initial Setup
1. SDK Warning ⚠️
DO NOT install the
openpaynpm 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:
- ✅ Webhook signature verification enabled
- ✅ All money stored in cents (BIGINT)
- ✅ Payment verification checks booking status
- ✅ Payment verification checks user ownership
- ✅ Environment variables secured (never in client code)
- ✅ HTTPS enabled for webhooks
- ✅ Card tokenization on client side (never send raw card data to server)
- ✅ Device session ID included for card payments (fraud detection)
Testing
Payment Flow
- Card: Immediate confirmation → booking
confirmed - SPEI: Shows CLABE/reference → webhook confirms (seconds)
- OXXO: Shows barcode → webhook confirms (24-72h)
Test Cards (Sandbox)
| Card Number | Result |
|---|---|
4111 1111 1111 1111 | Success |
4000 0000 0000 0002 | Insufficient 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.