{"_id":"@brandpos-sdk/expo-sdk","_rev":"2-4df6bf957e4608c00037f6b9c4b07464","name":"@brandpos-sdk/expo-sdk","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@brandpos-sdk/expo-sdk","version":"1.0.0","_id":"@brandpos-sdk/expo-sdk@1.0.0","maintainers":[{"name":"brandpos-sdk","email":"support@brandpos.de"}],"dist":{"shasum":"f867b1725681bfee23e8e7c275bd199ef26db437","tarball":"https://registry.npmjs.org/@brandpos-sdk/expo-sdk/-/expo-sdk-1.0.0.tgz","fileCount":7,"integrity":"sha512-RUVyRKf5+lmhv6XyOH/YvUQclq676tupqZKINeU2g4z6jMiQsHH4IuXDU2Q8CkS6OL4ut13b4LaomNfkfhwOWg==","signatures":[{"sig":"MEYCIQCjOJIPg/x4v6gjz0blrELVYaWjq2AJAMR10yMUH2AlQwIhANGozfEei1mW5WO0EqwlBMMpjX1+9PS3oyThPy/fguQM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82693},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.js","require":"./dist/index.js","react-native":"./dist/index.js"}},"gitHead":"cf0078905dd1d8c8be2076274b9d717f1514b66a","scripts":{"dev":"tsup src/index.ts --watch --format esm,cjs --dts","build":"tsup src/index.ts --format esm,cjs --dts","prepare":"npm run build"},"_npmUser":{"name":"brandpos-sdk","email":"support@brandpos.de"},"_npmVersion":"10.9.2","description":"BrandPOS V2 Expo and RN SDK","directories":{},"_nodeVersion":"22.17.0","dependencies":{"expo":">=49.0.0","react":"*","base-64":"^1.0.0","crypto-js":"^4.2.0","react-native":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"18.3.1","typescript":"^5.9.3","react-native":"0.76.9","@types/base-64":"^1.0.2","@types/crypto-js":"^4.2.2"},"peerDependencies":{"expo":">=49.0.0","react":"*","react-native":"*","@react-native-async-storage/async-storage":"*"},"_npmOperationalInternal":{"tmp":"tmp/expo-sdk_1.0.0_1778571335805_0.4934069797645091","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@brandpos-sdk/expo-sdk","version":"1.0.1","description":"BrandPOS V2 Expo and RN SDK","publishConfig":{"access":"public"},"main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"react-native":"./dist/index.js","import":"./dist/index.mjs","require":"./dist/index.js","types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsup src/index.ts --format esm,cjs --dts","dev":"tsup src/index.ts --watch --format esm,cjs --dts","prepare":"npm run build"},"dependencies":{"base-64":"^1.0.0","crypto-js":"^4.2.0","expo":">=49.0.0","react":"*","react-native":"*"},"peerDependencies":{"@react-native-async-storage/async-storage":"*","expo":">=49.0.0","react":"*","react-native":"*"},"devDependencies":{"@types/base-64":"^1.0.2","@types/crypto-js":"^4.2.2","react":"18.3.1","react-native":"0.76.9","tsup":"^8.0.0","typescript":"^5.9.3"},"_id":"@brandpos-sdk/expo-sdk@1.0.1","gitHead":"b3c1e14c314144cbb729125889056181dd172cf4","_nodeVersion":"22.17.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-LeDfo1nYqxqTpuBXUxLGjO71hCJNH99Z0MpguYS4sbiXu6g6Dz1hSwasz3rmkVUCntokC0Bjwb0qz++6aURVwA==","shasum":"3bed310a33164dd4c89298642da68382ad6e6070","tarball":"https://registry.npmjs.org/@brandpos-sdk/expo-sdk/-/expo-sdk-1.0.1.tgz","fileCount":7,"unpackedSize":90609,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDwtg4ADy9KYkgVu9Jp0WGVzTeEseGAoY1Jms+avCsAdwIgCWyKM+V1rUKLIiInrR/P8sdecUd2hZ4iDLq4f9zRzZ8="}]},"_npmUser":{"name":"brandpos-sdk","email":"support@brandpos.de"},"directories":{},"maintainers":[{"name":"brandpos-sdk","email":"support@brandpos.de"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/expo-sdk_1.0.1_1778681360932_0.7321871580957697"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-12T07:35:35.707Z","modified":"2026-05-13T14:09:21.267Z","1.0.0":"2026-05-12T07:35:35.941Z","1.0.1":"2026-05-13T14:09:21.150Z"},"description":"BrandPOS V2 Expo and RN SDK","maintainers":[{"name":"brandpos-sdk","email":"support@brandpos.de"}],"readme":"# BrandPOS V2 Expo SDK\n\nThe `@brandpos-sdk/expo-sdk` is a TypeScript SDK for Expo and React Native applications that integrates with the BrandPOS V2 API suite. It handles AES-256 request signing, device GUID persistence, session management, and provides a clean module-based interface for all BrandPOS operations.\n\n## Features\n\n- **Full TypeScript Support** — Comprehensive type definitions for all requests and responses.\n- **Secure Request Signing** — Automatic AES-256 encrypted `x-pos-sign` header on every call.\n- **Modular Design** — Organized into logical modules: Staff, Transaction, Terminal, POS, Payload, Feedback, Webhook, Invoice Mail, and mTLS.\n- **Expo / New Architecture Compatible** — Storage adapter pattern avoids direct AsyncStorage imports that crash in Expo Go with New Architecture enabled.\n- **Tree-shakeable** — Direct API module imports available for consumers who prefer them.\n- **Sandbox & Live Environments** — Switch between development and production with a single config flag.\n\n## Installation\n\n```bash\nnpm install @brandpos-sdk/expo-sdk\n# or\nyarn add @brandpos-sdk/expo-sdk\n```\n\n### Peer Dependencies\n\n```bash\nnpx expo install expo react react-native @react-native-async-storage/async-storage\n```\n\n> `@react-native-async-storage/async-storage` is optional but required for device GUID persistence across app restarts. Without it, the SDK falls back to an in-memory store.\n\n## Quick Start\n\n### 1. Initialization\n\n```typescript\nimport { BrandPosSDK } from '@brandpos-sdk/expo-sdk';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\n\nconst sdk = new BrandPosSDK({\n  environment: 'sandbox', // 'sandbox' | 'live'\n  lat: '53.5511',\n  lon: '9.9937',\n  storage: AsyncStorage,  // recommended for GUID persistence\n});\n```\n\n### 2. Staff Login\n\n```typescript\nconst loginRes = await sdk.staff.login({\n  uslogin: 'staff@example.com',\n  uspwd: 'your-secure-password',\n  lang: 'EN',\n});\n\n// API success status is 100\nif (loginRes.status === 100) {\n  if (loginRes.verify === 1) {\n    // OTP required — call loginVerify next\n  }\n\n  const session = {\n    token: loginRes.token,\n    authToken: loginRes.auth_token,\n  };\n}\n```\n\n### 3. OTP Verification (when `verify === 1`)\n\n```typescript\nconst verifyRes = await sdk.staff.loginVerify(\n  { otp: '123456', lang: 'EN' },\n  loginRes.token   // token from the login response\n);\n\nconst session = {\n  token: verifyRes.token,\n  authToken: verifyRes.auth_token,\n};\n```\n\n### 4. Create a Transaction\n\n```typescript\nconst tx = await sdk.transaction.create(\n  {\n    payment: 'PAYPAL',\n    amount: 10.50,\n    currency: 'EUR',\n    order_no: 'ORDER-123',\n  },\n  session\n);\n\nconsole.log('Transaction reference:', tx.tnu);\n```\n\n### 5. Credit Card Transaction (Novalnet)\n\nCredit card payments route through Novalnet. Provide `paymentData`, `paymentAccessKey`, and `api_sign` alongside the standard request:\n\n```typescript\nconst tx = await sdk.transaction.create(\n  {\n    payment: 'CREDITCARD',\n    amount: 49.99,\n    currency: 'EUR',\n    paymentAccessKey: 'your-novalnet-access-key',\n    api_sign: 'your-novalnet-api-signature',\n    paymentData: {\n      card_number: '4111 1111 1111 1111',\n      card_holder: 'John Doe',\n      card_expiry_month: '12',\n      card_expiry_year: '2027',\n      card_cvc: '123',\n    },\n  },\n  session\n);\n\n// Returns a redirect_url for the payment page\nconsole.log('Redirect:', tx.result?.redirect_url);\n```\n\n## Configuration\n\n| Property | Type | Required | Description |\n| :--- | :--- | :--- | :--- |\n| `environment` | `'sandbox' \\| 'live'` | Yes | API environment. Sandbox: `https://mas-plapi.brandpos.de`, Live: `https://api2.brandpos.de` |\n| `lat` | `string` | Yes | Device GPS latitude (must be −90 to 90). |\n| `lon` | `string` | Yes | Device GPS longitude (must be −180 to 180). |\n| `storage` | `StorageAdapter` | No | AsyncStorage-compatible adapter for persisting device GUID. Falls back to in-memory if omitted. |\n| `guid` | `string` | No | Optional pre-set device GUID override. |\n\n## Session Management\n\nMost authenticated API calls require a `BrandPosSession` object built from the login response:\n\n```typescript\nexport interface BrandPosSession {\n  token: string;     // Staff token (from login / loginVerify)\n  authToken: string; // Rolling auth token — rotates on every API response\n}\n```\n\n**Important:** Every API response returns a new `auth_token`. Update your stored session after each call to keep subsequent requests valid.\n\n```typescript\nconst res = await sdk.transaction.recent(session);\nsession.authToken = res.auth_token; // update rolling token\n```\n\n## Error Handling\n\nThe SDK throws `BrandPosApiError` when the API returns a non-100 status code:\n\n```typescript\nimport { BrandPosApiError } from '@brandpos-sdk/expo-sdk';\n\ntry {\n  const res = await sdk.staff.login({ uslogin: 'x@x.com', uspwd: 'wrong', lang: 'EN' });\n} catch (err) {\n  if (err instanceof BrandPosApiError) {\n    console.error(err.status);      // API status code\n    console.error(err.status_desc); // Human-readable description\n  }\n}\n```\n\n## API Reference\n\n### `sdk.staff` — Staff Authentication & Profiles\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `login` | `(req: LoginRequest) => LoginResponse` | Authenticate a staff member. Returns `verify: 1` when OTP is required. `lang` is required. |\n| `loginVerify` | `(req: LoginVerifyRequest, token: string) => LoginResponse` | Verify OTP. Pass the `token` from `login()`. |\n| `register` | `(req: RegisterRequest) => LoginResponse` | Register a new staff account. |\n| `forgotPassword` | `(req: ForgotPasswordRequest) => BaseResponse` | Initiate the forgot-password flow. |\n| `getProfile` | `(session: BrandPosSession) => ProfileResponse` | Get the authenticated staff member's profile. |\n| `logout` | `(session: BrandPosSession) => LogoutResponse` | Invalidate the current session. |\n\n### `sdk.transaction` — Payment Operations\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `create` | `(req: CreateTransactionRequest, session) => CreateTransactionResponse` | Create a transaction. For `CREDITCARD`, also provide `paymentData`, `paymentAccessKey`, and `api_sign`. |\n| `search` | `(req: SearchTransactionRequest, session) => SearchTransactionResponse` | Search transactions by date range. |\n| `recent` | `(session, params?) => RecentTransactionResponse` | Fetch the most recent transactions. |\n| `verifyStatus` | `(req: VerifyStatusRequest, session) => VerifyStatusResponse` | Poll the current status of a transaction by `tnu`. |\n| `dashboard` | `(req: DashboardRequest, session) => DashboardResponse` | Aggregated overview: counts by date, status, currency, and payment type. |\n| `refund` | `(req: RefundRequest, session) => RefundResponse` | Refund a transaction by `tnu`. |\n\n**Supported Payment Types (`PaymentType`):**\n`CREDITCARD` · `DIRECT_DEBIT_SEPA` · `APPLEPAY` · `GOOGLEPAY` · `PREPAYMENT` · `PAYPAL` · `WECHATPAY` · `INVOICE` · `CASHPAYMENT` · `QRBANKPAY` · `LINK` · `ALIPAY` · `IVR`\n\n### `sdk.terminal` — Terminal Management\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `register` | `() => RegisterTerminalResponse` | Register the device as a terminal. |\n| `track` | `(req: TrackTerminalRequest, session) => TrackTerminalResponse` | Track terminal status. |\n\n### `sdk.pos` — POS Configuration\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `getConnectors` | `(session) => PosConnectorsResponse` | List all available POS app connectors. |\n| `getConfig` | `(session) => PosConfigResponse` | Get the current POS app configuration. |\n\n### `sdk.payload` — Transaction Payloads\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `getRecent` | `(session) => RecentPayloadResponse` | Retrieve the most recent transaction payload. |\n\n### `sdk.feedback` — User Feedback\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `submit` | `(req: FeedbackRequest, session) => FeedbackResponse` | Submit user feedback with an optional rating and comment. |\n\n### `sdk.webhook` — Webhook Events\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `handle` | `(req: WebhookHandlerRequest, session) => WebhookHandlerResponse` | Process an incoming webhook event payload. |\n\n### `sdk.invoiceMail` — Invoice Email\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `send` | `(req: InvoiceMailRequest, session) => InvoiceMailResponse` | Send an invoice email for a transaction. |\n| `share` | `(req: ShareInvoiceRequest, session) => InvoiceMailResponse` | Share an invoice link via email. |\n\n### `sdk.mtls` — mTLS Certificates\n\n| Method | Signature | Description |\n| :--- | :--- | :--- |\n| `getDetails` | `(session) => MtlsDetailsResponse` | Retrieve mTLS certificate details for the device. |\n\n## Tree-shakeable Imports\n\nFor consumers who prefer direct module imports (better tree-shaking):\n\n```typescript\nimport { staffApi, transactionApi, terminalApi } from '@brandpos-sdk/expo-sdk';\n\n// Build headers manually if needed\nimport { buildAuthHeaders } from '@brandpos-sdk/expo-sdk';\n```\n\nAvailable namespaces: `staffApi`, `transactionApi`, `terminalApi`, `posApi`, `payloadApi`, `feedbackApi`, `webhookApi`, `invoiceMailApi`, `mtlsApi`.\n\n## Storage Adapter\n\nThe SDK never imports `@react-native-async-storage/async-storage` directly. Pass it in via `storage` to avoid the \"Native module is null\" crash in Expo Go with New Architecture:\n\n```typescript\nimport AsyncStorage from '@react-native-async-storage/async-storage';\n\nconst sdk = new BrandPosSDK({\n  environment: 'sandbox',\n  lat: '53.5511',\n  lon: '9.9937',\n  storage: AsyncStorage,\n});\n```\n\nAny object implementing `{ getItem, setItem, removeItem }` is compatible. Without a `storage` adapter, the device GUID is kept in memory and will not persist across app restarts.\n\n## Building\n\n```bash\nnpm run build   # compile to dist/ (ESM + CJS + .d.ts)\nnpm run dev     # watch mode\n```\n\nOutput files:\n- `dist/index.js` — CommonJS\n- `dist/index.mjs` — ESM\n- `dist/index.d.ts` — Type declarations\n","readmeFilename":"Readme.md"}