{"_id":"unuspay-sdk","_rev":"2-4763c0fb189e5f286f0581520ca5bb28","name":"unuspay-sdk","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"unuspay-sdk","version":"0.1.0","keywords":["unuspay","webhook","signature","verification","payments"],"author":{"name":"UnusPay"},"license":"MIT","_id":"unuspay-sdk@0.1.0","maintainers":[{"name":"gjuoun","email":"gjuoun@gmail.com"}],"dist":{"shasum":"7594ac7eb7a92ad6319a40d1f30ae6ea329c6d2c","tarball":"https://registry.npmjs.org/unuspay-sdk/-/unuspay-sdk-0.1.0.tgz","fileCount":6,"integrity":"sha512-lBnqMNsqvuBeu6kYr7b3g8NLsyXgX95J1K8cC4lVzRrutHpWE59ds2pc6oTyDBbrTZYxBlpKr/6sdneWXkG/7w==","signatures":[{"sig":"MEUCIFhAlfhfmDncz6DPlw+9QRNEM9tSyyJlW6zX3IvurgqwAiEArLx/z3zTb8o5fWIF+HHM8xIQT3OPTuOw8yfPdtVtLBg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":20674},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"cc77c46ae4c0d2657cc1d17f9ed3a743519baa65","scripts":{"test":"bun test src/index.test.ts","build":"tsup src/index.ts --format cjs,esm --dts","test:node":"vitest run","prepublishOnly":"npm run build"},"_npmUser":{"name":"gjuoun","email":"gjuoun@gmail.com"},"_npmVersion":"10.9.4","description":"Official UnusPay SDK for webhook verification","directories":{},"_nodeVersion":"22.21.0","dependencies":{"zod":"^4.3.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.0.0","@types/node":"^18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/unuspay-sdk_0.1.0_1773049005261_0.001638594923567771","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"unuspay-sdk","version":"0.1.1","description":"Official UnusPay SDK for webhook verification","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup src/index.ts --format cjs,esm --dts","test":"bun test src/index.test.ts","test:node":"vitest run","prepublishOnly":"npm run build"},"keywords":["unuspay","webhook","signature","verification","payments"],"author":{"name":"UnusPay"},"license":"MIT","dependencies":{"zod":"^4.3.6"},"devDependencies":{"@types/node":"^18.0.0","tsup":"^8.0.0","typescript":"^5.0.0","vitest":"^2.0.0"},"engines":{"node":">=18"},"_id":"unuspay-sdk@0.1.1","gitHead":"23b54c73b45b4de3ae0d69c307973140ac0da92f","_nodeVersion":"22.21.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-h/MmmHbEmTonNTxTdJ0/o4YFW6+mkg5y/qPCfz91ZmaMDBHIf20jJVy8V7y+wCt41VBeo8IqvUi8kcsMH4UvEw==","shasum":"4d4850d6bce8f9dd4d3257e5bd4e389471f47072","tarball":"https://registry.npmjs.org/unuspay-sdk/-/unuspay-sdk-0.1.1.tgz","fileCount":6,"unpackedSize":20665,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDdtDf66VlIxPfG3q7RkcEAjdARuA9Mden3UHFucbqYygIgHdm/UlP6iIFNXh1iOnxD8yNl+lv1DzGqW5KvV97pUq0="}]},"_npmUser":{"name":"gjuoun","email":"gjuoun@gmail.com"},"directories":{},"maintainers":[{"name":"gjuoun","email":"gjuoun@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/unuspay-sdk_0.1.1_1773050144633_0.3992610153871523"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-09T09:36:45.260Z","modified":"2026-03-09T09:55:44.901Z","0.1.0":"2026-03-09T09:36:45.423Z","0.1.1":"2026-03-09T09:55:44.765Z"},"author":{"name":"UnusPay"},"license":"MIT","keywords":["unuspay","webhook","signature","verification","payments"],"description":"Official UnusPay SDK for webhook verification","maintainers":[{"name":"gjuoun","email":"gjuoun@gmail.com"}],"readme":"# unuspay-sdk\n\nOfficial UnusPay SDK for webhook signature verification.\n\n## Installation\n\n```bash\nnpm install unuspay-sdk\n# or\nyarn add unuspay-sdk\n# or\npnpm add unuspay-sdk\n```\n\n## Usage\n\n### Express\n\n```typescript\nimport express from 'express'\nimport { Webhook, WebhookVerificationError } from 'unuspay-sdk'\n\nconst app = express()\n\n// Create a reusable webhook verifier instance\nconst webhook = new Webhook(process.env.WEBHOOK_SECRET!)\n\n// IMPORTANT: Use raw body for webhook routes\napp.post('/webhook',\n  express.raw({ type: 'application/json' }),\n  (req, res) => {\n    try {\n      const event = webhook.verify(\n        req.body.toString(),\n        req.headers['x-webhook-signature'] as string,\n        req.headers['x-webhook-timestamp'] as string\n      )\n\n      // Handle the event\n      switch (event.type) {\n        case 'order.completed':\n          console.log('Order completed:', event.data)\n          break\n        case 'payment_link.created':\n          console.log('Payment link created:', event.data)\n          break\n      }\n\n      res.json({ received: true })\n    } catch (error) {\n      if (error instanceof WebhookVerificationError) {\n        console.error('Webhook verification failed:', error.message)\n        return res.status(401).json({ error: error.message })\n      }\n      throw error\n    }\n  }\n)\n```\n\n### Next.js (App Router)\n\n```typescript\n// app/api/webhook/route.ts\nimport { Webhook, WebhookVerificationError } from 'unuspay-sdk'\nimport { NextRequest, NextResponse } from 'next/server'\n\n// Create a reusable webhook verifier instance\nconst webhook = new Webhook(process.env.WEBHOOK_SECRET!)\n\nexport async function POST(req: NextRequest) {\n  try {\n    const payload = await req.text()  // Get raw body\n    \n    const event = webhook.verify(\n      payload,\n      req.headers.get('x-webhook-signature')!,\n      req.headers.get('x-webhook-timestamp')!\n    )\n\n    // Handle event...\n    console.log('Received event:', event.type)\n\n    return NextResponse.json({ received: true })\n  } catch (error) {\n    if (error instanceof WebhookVerificationError) {\n      return NextResponse.json({ error: error.message }, { status: 401 })\n    }\n    throw error\n  }\n}\n```\n\n### Bun / Elysia\n\n```typescript\nimport { Elysia } from 'elysia'\nimport { Webhook } from 'unuspay-sdk'\n\n// Create a reusable webhook verifier instance\nconst webhook = new Webhook(process.env.WEBHOOK_SECRET!)\n\nnew Elysia()\n  .post('/webhook', async ({ request }) => {\n    const payload = await request.text()\n    \n    const event = webhook.verify(\n      payload,\n      request.headers.get('x-webhook-signature')!,\n      request.headers.get('x-webhook-timestamp')!\n    )\n\n    return { received: true, type: event.type }\n  })\n  .listen(3000)\n```\n\n## API Reference\n\n### `Webhook` class\n\nThe main class for webhook signature verification.\n\n#### Constructor\n\n```typescript\nnew Webhook(secret: string, config?: WebhookConfig)\n```\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `secret` | `string` | Yes | Your webhook secret (starts with `whsec_`) |\n| `config` | `WebhookConfig` | No | Optional configuration |\n\n**WebhookConfig:**\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `maxAgeSeconds` | `number` | `300` | Max event age in seconds |\n\n#### `verify(payload, signature, timestamp)`\n\nVerifies a webhook signature and returns the parsed payload.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `payload` | `string` | Yes | Raw request body (NOT parsed JSON) |\n| `signature` | `string` | Yes | Value of `X-Webhook-Signature` header |\n| `timestamp` | `string \\| number` | Yes | Value of `X-Webhook-Timestamp` header |\n\n**Returns:** Parsed event object\n\n**Throws:** `WebhookVerificationError` if verification fails\n\n**Example:**\n\n```typescript\nconst webhook = new Webhook(process.env.WEBHOOK_SECRET!)\n\nconst event = webhook.verify(\n  rawBody,\n  headers['x-webhook-signature'],\n  headers['x-webhook-timestamp']\n)\n```\n\n### `WebhookVerificationError`\n\nError thrown when verification fails.\n\n**Properties:**\n- `message`: Human-readable error message\n- `code`: Error code (`'INVALID_SIGNATURE'` | `'TIMESTAMP_EXPIRED'` | `'MISSING_HEADERS'`)\n\n## Important: Raw Body Required\n\nWebhook signature verification requires the **raw request body** (exact bytes as received). If your framework parses JSON automatically, the signature will fail.\n\n**Common solutions:**\n\n- **Express:** Use `express.raw({ type: 'application/json' })` middleware\n- **Next.js:** Use `await req.text()` instead of `await req.json()`\n- **Fastify:** Use `{ parseAs: 'string' }` in route config\n\n## License\n\nMIT\n","readmeFilename":"README.md"}