{"id":50867848,"url":"https://github.com/validpay-io/validpay-react-native-sdk","last_synced_at":"2026-06-15T03:01:15.462Z","repository":{"id":363931883,"uuid":"1228209547","full_name":"ValidPay-io/validpay-react-native-sdk","owner":"ValidPay-io","description":"Official React Native SDK for ValidPay CVCP — QR-based cryptographic document verification for mobile apps.","archived":false,"fork":false,"pushed_at":"2026-06-10T22:55:47.000Z","size":78,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-11T01:22:20.551Z","etag":null,"topics":["check-fraud","cryptography","document-verification","mobile-sdk","qr-verification","react-native"],"latest_commit_sha":null,"homepage":"https://validpay.io","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ValidPay-io.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-03T18:31:23.000Z","updated_at":"2026-06-09T23:41:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ValidPay-io/validpay-react-native-sdk","commit_stats":null,"previous_names":["validpay-io/validpay-react-native-sdk"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ValidPay-io/validpay-react-native-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValidPay-io%2Fvalidpay-react-native-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValidPay-io%2Fvalidpay-react-native-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValidPay-io%2Fvalidpay-react-native-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValidPay-io%2Fvalidpay-react-native-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ValidPay-io","download_url":"https://codeload.github.com/ValidPay-io/validpay-react-native-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValidPay-io%2Fvalidpay-react-native-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34345578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["check-fraud","cryptography","document-verification","mobile-sdk","qr-verification","react-native"],"created_at":"2026-06-15T03:01:14.768Z","updated_at":"2026-06-15T03:01:15.456Z","avatar_url":"https://github.com/ValidPay-io.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @validpay/react-native-sdk\n\n[![Tests](https://github.com/ValidPay-io/validpay-react-native-sdk/actions/workflows/test.yml/badge.svg)](https://github.com/ValidPay-io/validpay-react-native-sdk/actions/workflows/test.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nOfficial React Native SDK for the [ValidPay](https://validpay.com) document\nverification API. AES-256-GCM client-side encryption, eight patented\nprotections, and zero runtime dependencies.\n\nThe wire format is byte-compatible with the [Python SDK][python-sdk] and the\n[Node SDK][node-sdk] — an intent created with any ValidPay SDK can be\nverified with any other.\n\n[python-sdk]: https://github.com/ValidPay-io/validpay-python-sdk\n[node-sdk]: https://github.com/ValidPay-io/validpay-node-sdk\n\n## Installation\n\n```bash\nnpm install @validpay/react-native-sdk\n```\n\n## Setup — pluggable crypto backend\n\nReact Native does not include Web Crypto. Apps choose their own AES-256-GCM\nimplementation (`expo-crypto`, `react-native-quick-crypto`, Web Crypto on\nRN-future, etc.) and inject it once at startup. The SDK uses your\nimplementation everywhere — there's no native module bundled.\n\n```ts\nimport { configure, CryptoProvider } from '@validpay/react-native-sdk';\nimport * as ExpoCrypto from 'expo-crypto';\n\nclass ExpoCryptoProvider implements CryptoProvider {\n  async getRandomBytes(length: number): Promise\u003cUint8Array\u003e {\n    return ExpoCrypto.getRandomBytes(length);\n  }\n  async encrypt(plaintext: Uint8Array, key: Uint8Array): Promise\u003cstring\u003e {\n    // AES-256-GCM with a fresh 12-byte IV. Return base64 string of:\n    //   iv (12 bytes) || authTag (16 bytes) || ciphertext\n    // ...consult expo-crypto / react-native-quick-crypto docs for the call.\n  }\n  async decrypt(ciphertext: string, key: Uint8Array): Promise\u003cUint8Array\u003e { /* … */ }\n  async sha256(data: Uint8Array): Promise\u003cstring\u003e {\n    return ExpoCrypto.digestStringAsync(\n      ExpoCrypto.CryptoDigestAlgorithm.SHA256,\n      Buffer.from(data).toString('base64'),\n      { encoding: ExpoCrypto.CryptoEncoding.HEX },\n    );\n  }\n}\n\nconfigure({ crypto: new ExpoCryptoProvider() });\n```\n\nIf you use `splitKey()`, also import a synchronous random-bytes polyfill\nonce at app entry:\n\n```ts\nimport 'react-native-get-random-values';\n```\n\nThis provides `globalThis.crypto.getRandomValues`, which `splitKey()` needs\nsynchronously.\n\n## Quick start\n\n```ts\nimport { ValidPayClient } from '@validpay/react-native-sdk';\n\nconst client = new ValidPayClient({ apiKey: 'vp_live_…' });\n\n// Issue\nconst result = await client.createIntent('check', {\n  payee: 'Alice',\n  amount: 1500,\n});\nconsole.log(result.retrievalId, result.key);\n// → vp_abc123…   (embed in QR)\n// → base64 AES key — print on document, never store\n\n// Verify (no API key required)\nconst verified = await client.verifyIntent(result.retrievalId, result.key);\nconsole.log(verified.payload);          // { payee: 'Alice', amount: 1500 }\nconsole.log(verified.integrityVerified); // true\n```\n\n## Features\n\nEight patented protections, all live in this SDK:\n\n| Patent | Feature                       | Method                                              |\n| ------ | ----------------------------- | --------------------------------------------------- |\n| A      | Multi-Hash Verification       | `computeCommitmentHash`, automatic on verify        |\n| B      | Blind Content Escrow          | `encrypt` / `decrypt` (client-side AES-256-GCM)     |\n| C      | Split-Key Verification        | `createSplitKeyIntent` / `verifySplitKeyIntent`     |\n| D      | Time-Locked Verification      | `validFrom` / `validUntil` on all create methods    |\n| E      | Selective Field Disclosure    | `createSelectiveIntent` / `verifySelectiveIntent`   |\n| F      | Chain-of-Custody Tracking     | `getRevocationHistory`                              |\n| G      | Physical Medium Binding       | `computeBindingHash`, `createBoundIntent`           |\n| H      | Blind Revocation              | `revokeIntent` / `reinstateIntent`                  |\n\n## API reference\n\n### `new ValidPayClient(options)`\n\n| Option      | Type     | Default                       | Notes                                    |\n| ----------- | -------- | ----------------------------- | ---------------------------------------- |\n| `apiKey`    | `string` | required                      | Bearer key from the issuer dashboard.    |\n| `baseUrl`   | `string` | `https://api.validpay.com`    | Override for staging.                    |\n| `timeoutMs` | `number` | `10000`                       | Per-request timeout (AbortController).   |\n\n### Core methods\n\n```ts\nclient.createIntent(documentType, payload, opts?): Promise\u003cCreateIntentResult\u003e\nclient.createIntentBatch(intents): Promise\u003cCreateIntentResult[]\u003e   // ≤100 items\nclient.verifyIntent(retrievalId, key): Promise\u003cVerifyIntentResult\u003e\n```\n\n### Split-key (Patent C)\n\n```ts\nclient.createSplitKeyIntent(documentType, payload, opts?): Promise\u003cCreateIntentResult\u003e\nclient.verifySplitKeyIntent(retrievalId, shareA): Promise\u003cVerifyIntentResult\u003e\n```\n\n`createSplitKeyIntent` returns Share A as the `key` field — embed it on the\ndocument as you would the regular key. Share B stays on the server and is\nfetched at verify time.\n\n### Selective disclosure (Patent E)\n\n```ts\nclient.createSelectiveIntent(\n  documentType,\n  payload,                                 // { fieldName: value }\n  policy,                                  // { roleName: ['fieldName', …] }\n  opts?,                                   // { splitKey?, validFrom?, validUntil? }\n): Promise\u003cCreateIntentResult\u003e\n\nclient.verifySelectiveIntent(\n  retrievalId,\n  key,\n  role = 'full',                           // 'full' decrypts everything\n): Promise\u003cVerifyIntentResult\u003e\n```\n\nA `full` role with every field key is added to the policy automatically —\nthat's the issuer view.\n\n### Time-locked verification (Patent D)\n\n`validFrom` / `validUntil` (ISO-8601 strings) are accepted on every create\nmethod. Every verify result includes `timeLockStatus` (`'valid'`,\n`'not_yet_valid'`, `'expired'`, or `null`). The SDK never withholds the\npayload — the caller decides whether to surface the status to the user.\n\n```ts\nconst result = await client.createIntent('check', payload, {\n  validFrom:  '2026-06-01T00:00:00Z',\n  validUntil: '2026-12-31T23:59:59Z',\n});\n\nconst verified = await client.verifyIntent(result.retrievalId, result.key);\n// verified.timeLockStatus → 'valid' | 'not_yet_valid' | 'expired'\n```\n\n### Revocation (Patent H)\n\n```ts\nclient.revokeIntent(retrievalId, reason?): Promise\u003c…\u003e\nclient.reinstateIntent(retrievalId, reason?): Promise\u003c…\u003e\nclient.getRevocationHistory(retrievalId): Promise\u003cArray\u003c…\u003e\u003e\n```\n\nRevocation is \"blind\" — the server flips a status bit and stops returning\nthe ciphertext. It never decrypts the payload.\n\n### Physical medium binding (Patent G)\n\n```ts\nimport { computeBindingHash, compareBindingHashes } from '@validpay/react-native-sdk';\n\n// Pre-process the binding-zone image to 8×8 grayscale with your image lib\n// (expo-image-manipulator, react-native-image-resizer, etc.) and pass the\n// raw bytes — this SDK doesn't bundle a JPEG/PNG decoder.\nconst imageBytes = new Uint8Array(64);     // 8×8 grayscale\nconst hash = await computeBindingHash(imageBytes);\n\nconst result = compareBindingHashes(hashA, hashB, /* threshold */ 10);\nresult.match;     // boolean\nresult.distance;  // Hamming distance\n```\n\n`createBoundIntent` issues a binding-aware intent in one call:\n\n```ts\nconst result = await client.createBoundIntent(\n  'check',\n  { payee: 'Alice', amount: 1500 },\n  bindingZoneImage,\n  { threshold: 10 },\n);\n```\n\n### Errors\n\nEvery SDK and API failure is thrown as `ValidPayError`:\n\n```ts\nimport { ValidPayError } from '@validpay/react-native-sdk';\n\ntry {\n  await client.verifyIntent('vp_missing', 'key');\n} catch (e) {\n  if (e instanceof ValidPayError) {\n    e.code;     // 'not_found' | 'unauthorized' | 'integrity_failure' | …\n    e.status;   // HTTP status, when the error came from the API\n    e.details;  // raw error body / extra context\n  }\n}\n```\n\n## Cross-SDK compatibility\n\nThe wire format is identical across the Python, Node, and React Native SDKs:\n\n```\nbase64(iv[12 bytes] || authTag[16 bytes] || ciphertext)\n```\n\nAn intent created with `validpay` (Python) can be verified with this SDK,\nand vice versa. Tests in `__tests__/crypto.test.ts` decrypt a hand-crafted\nblob in the Python wire layout to enforce this guarantee.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalidpay-io%2Fvalidpay-react-native-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalidpay-io%2Fvalidpay-react-native-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalidpay-io%2Fvalidpay-react-native-sdk/lists"}