{"_id":"9pay-integrate","_rev":"2-3328a3508b470251bc7e87f7b140ee27","name":"9pay-integrate","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"9pay-integrate","version":"1.0.0","keywords":["9pay","payment","payment-gateway","vietnam","nextjs","typescript"],"license":"MIT","_id":"9pay-integrate@1.0.0","maintainers":[{"name":"birthdayn","email":"nhatnguyendev251@gmail.com"}],"dist":{"shasum":"5d59f8189e0ea8d837b234dc4e91c2fdf34cc3bb","tarball":"https://registry.npmjs.org/9pay-integrate/-/9pay-integrate-1.0.0.tgz","fileCount":10,"integrity":"sha512-IzUGzYHxR/kYAdh5l9Pw9PG0ItX49oxDhzKNn/HfXQDkny5Pe+EiozRgWWrLjchYRsHmcw8zWaUhKgSEYgvRgQ==","signatures":[{"sig":"MEYCIQC97Sy9oPs/Y3MK+auGctB3X01P/GqRE4LxgKgvjVfQLQIhAMssjc9y/k/szz3cS9y6ThbNUAbbch3yfqACiCuIE/yn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62955},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./next":{"import":{"types":"./dist/next/index.d.ts","default":"./dist/next/index.js"},"require":{"types":"./dist/next/index.d.cts","default":"./dist/next/index.cjs"}}},"gitHead":"971ed852465f96f8142288cf3aefd1429b7519aa","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"birthdayn","email":"nhatnguyendev251@gmail.com"},"_npmVersion":"10.9.3","description":"Complete 9Pay payment gateway integration for Node.js and Next.js","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"next":">=14.0.0","tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.0.0","@types/node":"^20.0.0"},"peerDependencies":{"next":">=14.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/9pay-integrate_1.0.0_1780489867040_0.35418348516873177","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"_id":"9pay-integrate@1.0.1","bugs":{"url":"https://github.com/nhat251/9pay-integrate/issues"},"dist":{"shasum":"4a5da05ca522424c52924f235e7bdffe2850d4a1","tarball":"https://registry.npmjs.org/9pay-integrate/-/9pay-integrate-1.0.1.tgz","fileCount":10,"integrity":"sha512-IJYyECTN+irZpSqltYYqza0KUlyv2KtO7ZUXWde++zvu7WfUtuVzfP64KFuoaaM2p0vCg6PwioWUyZJ/4+CykA==","signatures":[{"sig":"MEQCIBvGLbyDMGurFjLsi+cXvz1TdqUHU/ERI//XGGTlptUuAiBosO/1a6ubzd+FjESKY+J1H83sGaGUs9nTOvM7ACFalw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCra/5Gc34/lELxcy2ZNysb1exrg/8Fti6p1RoDs10AMwIgFLqssZYsfurpAjCangDBMcgXIyjHFXprUlOEHH6HBoE="}],"unpackedSize":63330},"main":"./dist/index.cjs","name":"9pay-integrate","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./next":{"import":{"types":"./dist/next/index.d.ts","default":"./dist/next/index.js"},"require":{"types":"./dist/next/index.d.cts","default":"./dist/next/index.cjs"}}},"gitHead":"7cf96c816ea1dae6cbceaee51205a4e7b4078b36","license":"MIT","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest"},"version":"1.0.1","_npmUser":{"name":"birthdayn","email":"nhatnguyendev251@gmail.com"},"homepage":"https://github.com/nhat251/9pay-integrate#readme","keywords":["9pay","payment","payment-gateway","vietnam","nextjs","typescript"],"repository":{"url":"git+https://github.com/nhat251/9pay-integrate.git","type":"git"},"_npmVersion":"10.9.3","description":"Complete 9Pay payment gateway integration for Node.js and Next.js","directories":{},"maintainers":[{"name":"birthdayn","email":"nhatnguyendev251@gmail.com"}],"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"next":">=14.0.0","tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.0.0","@types/node":"^20.0.0"},"peerDependencies":{"next":">=14.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/9pay-integrate_1.0.1_1789527321362_0.887231932277802"}}},"time":{"created":"2026-06-03T12:31:06.895Z","modified":"2026-09-16T02:55:21.607Z","1.0.0":"2026-06-03T12:31:07.207Z","1.0.1":"2026-09-16T02:55:21.439Z"},"license":"MIT","keywords":["9pay","payment","payment-gateway","vietnam","nextjs","typescript"],"description":"Complete 9Pay payment gateway integration for Node.js and Next.js","maintainers":[{"name":"birthdayn","email":"nhatnguyendev251@gmail.com"}],"readme":"# 9pay-integrate\n\nComplete 9Pay payment gateway integration for Node.js and Next.js. Generate payment URLs, verify callbacks, process IPN webhooks — all with a clean, framework-agnostic core.\n\n```bash\npnpm install 9pay-integrate\n```\n\n## Quick Start\n\n### 1. Configure\n\n```typescript\n// lib/9pay-config.ts\nimport { configFromEnv } from \"9pay-integrate\";\n\nexport const ninepay = configFromEnv(process.env);\n```\n\nRequired environment variables:\n- `NINEPAY_MERCHANT_KEY`\n- `NINEPAY_SECRET_KEY`\n- `NINEPAY_CHECKSUM_KEY`\n- `NINEPAY_RETURN_URL` (e.g. `https://yoursite.com/api/checkout/9pay/callback`)\n\nOptional:\n- `NINEPAY_BASE_URL` (default: `https://payment.9pay.vn`)\n- `NINEPAY_CANCEL_URL` (default: same as RETURN_URL)\n\n### 2. Implement Order Repository\n\nThe package needs a way to manage orders. Implement the `OrderRepository` interface for your data layer (Strapi, Prisma, Drizzle, MongoDB, REST API, etc.).\n\n```typescript\n// lib/order-repository.ts\nimport type { OrderRepository, OrderStatus } from \"9pay-integrate\";\n\nexport const repo: OrderRepository = {\n  async createOrder(params) {\n    // Create order in your database\n    // Return whatever your DB returns\n  },\n  async getOrderStatus(orderId: string): Promise<OrderStatus | null> {\n    // Query order status from your database\n    // Return \"neworder\" | \"pending\" | \"completed\" | \"failed\" | null\n  },\n  async updateOrderStatus(orderId: string, status: \"completed\" | \"failed\") {\n    // Update order status in your database\n    // Return the updated order or null\n  },\n};\n```\n\n### 3. Implement Notification Hooks (optional)\n\n```typescript\n// lib/notifications.ts\nimport type { NotificationContext } from \"9pay-integrate\";\n\nexport const notifications = {\n  async onSuccess(ctx: NotificationContext) {\n    // Send confirmation email\n    // Send Telegram/Slack notification\n    console.log(`Order ${ctx.orderId} completed: ${ctx.amount} ${ctx.currency}`);\n  },\n  async onFailure(ctx: NotificationContext) {\n    // Alert on payment failure\n    console.log(`Order ${ctx.orderId} failed`);\n  },\n};\n```\n\n### 4. Create Payment URL (Checkout POST)\n\nIn your checkout API route, create the order in your database, then generate the 9Pay redirect URL.\n\n```typescript\n// app/api/checkout/route.ts\nimport { NextResponse } from \"next/server\";\nimport { createPaymentUrl } from \"9pay-integrate\";\nimport { ninepay } from \"@/lib/9pay-config\";\nimport { repo } from \"@/lib/order-repository\";\n\nexport async function POST(request: Request) {\n  const body = await request.json();\n\n  // 1. Validate checkout form data, calculate pricing, etc.\n  // 2. Create order in your database\n  const order = await repo.createOrder({\n    totalAmount: body.amount,\n    currency: body.currency,\n    paymentMethod: \"9pay\",\n    metadata: body,\n  });\n\n  // 3. Generate 9Pay payment URL\n  const paymentUrl = createPaymentUrl(ninepay, {\n    orderId: order.id, // or order.documentId, whatever your DB returns\n    amount: body.amount,\n    currency: body.currency,\n    description: \"Order Payment\",\n  });\n\n  return NextResponse.json({ success: true, orderId: order.id, paymentUrl });\n}\n```\n\n### 5. Wire Up Routes\n\n#### Callback Route (GET)\n\nHandles the browser redirect after payment on 9Pay's portal.\n\n```typescript\n// app/api/checkout/9pay/callback/route.ts\nimport { NextResponse } from \"next/server\";\nimport { verifyNinePayCallback } from \"9pay-integrate/next\";\nimport { ninepay } from \"@/lib/9pay-config\";\n\nexport async function GET(request: Request) {\n  const result = verifyNinePayCallback(request, ninepay);\n\n  if (!result.success) {\n    return NextResponse.redirect(new URL(\"/payment/error\", request.url));\n  }\n\n  return NextResponse.redirect(\n    new URL(`/payment/process?orderId=${result.orderId}`, request.url)\n  );\n}\n```\n\n#### IPN Webhook (POST)\n\nHandles the server-to-server webhook from 9Pay. This is the source of truth for payment status.\n\n```typescript\n// app/api/checkout/9pay/ipn/route.ts\nimport { handle9PayIpn } from \"9pay-integrate/next\";\nimport { ninepay } from \"@/lib/9pay-config\";\nimport { repo } from \"@/lib/order-repository\";\nimport { notifications } from \"@/lib/notifications\";\n\nexport async function POST(request: Request) {\n  return handle9PayIpn(request, {\n    config: ninepay,\n    orderRepository: repo,\n    notifications,\n  });\n}\n```\n\n#### Payment Status (GET)\n\nFor frontend polling.\n\n```typescript\n// app/api/payment/status/route.ts\nimport { handlePaymentStatus } from \"9pay-integrate/next\";\nimport { repo } from \"@/lib/order-repository\";\n\nexport async function GET(request: Request) {\n  return handlePaymentStatus(request, { orderRepository: repo });\n}\n```\n\n## API Reference\n\n### Core (`9pay-integrate`)\n\n| Export | Description |\n|--------|-------------|\n| `configFromEnv(env)` | Build config from any env-like object |\n| `validateConfig(partial)` | Validate and normalize config |\n| `createPaymentUrl(config, params)` | Generate signed 9Pay redirect URL |\n| `verifyChecksum(result, checksum, key)` | Verify callback/IPN checksum |\n| `verifyCallback(searchParams, config)` | Verify browser redirect callback |\n| `processIpn(payload, options)` | Process IPN (adapter-agnostic) |\n| `buildHttpQuery(data)` | Build sorted query string (advanced) |\n| `buildSignature(baseUrl, time, query, key)` | Build HMAC signature (advanced) |\n| `extractIpnFromFormData(formData)` | Extract IPN from FormData |\n| `extractIpnFromUrlEncoded(body)` | Extract IPN from URL-encoded body |\n| `NINEPAY_STATUS` | Status codes (SUCCESS = 5) |\n| `SUCCESS_STATUS` | Constant for successful payment |\n\n### Next.js Adapter (`9pay-integrate/next`)\n\n| Export | Description |\n|--------|-------------|\n| `verifyNinePayCallback(request, config)` | Verify callback, return result object |\n| `handle9PayIpn(request, options)` | Full IPN handler → NextResponse |\n| `handlePaymentStatus(request, options)` | Status polling handler → NextResponse |\n\n### Types\n\nAll types are exported from the main entry point. Key interfaces:\n\n- `NinePayConfig` — configuration\n- `OrderRepository` — implement for your data layer\n- `NotificationHooks` — optional notification callbacks\n- `IpnProcessResult` — IPN processing result\n- `VerifyCallbackResult` — callback verification result\n- `OrderStatus` — `\"neworder\" | \"pending\" | \"completed\" | \"failed\"`\n\n## Architecture\n\n```\n┌─────────────────────────────────────────┐\n│           9Pay Portal                    │\n│      payment.9pay.vn/portal              │\n└────────────┬────────────────┬───────────┘\n             │                │\n      Browser redirect    Server-to-server\n        (callback GET)        (IPN POST)\n             │                │\n┌────────────▼────────────────▼───────────┐\n│              9pay-integrate/core         │\n│  ┌─────────┐  ┌───────────┐  ┌───────┐  │\n│  │ signing  │  │ verify    │  │ ipn   │  │\n│  │ +payment │  │ callback  │  │ proc  │  │\n│  └─────────┘  └───────────┘  └───────┘  │\n│            (zero framework deps)         │\n└────────────────┬────────────────────────┘\n                 │\n┌────────────────▼────────────────────────┐\n│          9pay-integrate/next             │\n│  (thin glue: parse req → call core)      │\n└─────────────────────────────────────────┘\n```\n\n### Design Principles\n\n1. **Core has zero framework dependencies** — works in Express, Fastify, Hono, Bun, Deno\n2. **Inversion of Control** — package never hardcodes ORM/CMS/notification service\n3. **Option B for callback** — returns data, consumer controls redirect\n4. **Option C for IPN** — encapsulates all 6 steps, but consumer can bypass and call `processIpn()` directly from core\n5. **Fail fast** — config validation at init time, not during live payment\n\n## Support\n\nFound a bug or have a feature request?\n\n[Create an issue](https://github.com/nhat251/9pay-integrate/issues/new)\n\n## License\n\nMIT\n","readmeFilename":"README.md","homepage":"https://github.com/nhat251/9pay-integrate#readme","repository":{"url":"git+https://github.com/nhat251/9pay-integrate.git","type":"git"},"bugs":{"url":"https://github.com/nhat251/9pay-integrate/issues"}}