### Quick Start Example Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/java.md Demonstrates how to initialize the client and perform a key handshake to authenticate a user. ```APIDOC ## Quick Start ```java import cc.getportal.PortalClient; import cc.getportal.PortalClientConfig; PortalClient client = new PortalClient( PortalClientConfig.create("http://localhost:3000", "your-auth-token") ); // Authenticate a user var operation = client.newKeyHandshakeUrl(); System.out.println("Share with user: " + operation.url()); var result = client.pollUntilComplete(operation); System.out.println("User key: " + result.main_key()); ``` ``` -------------------------------- ### Install Dependencies Source: https://github.com/portaltechnologiesinc/lib/blob/master/examples/README.md Navigate to the examples directory and install project dependencies using npm. ```bash cd examples npm install ``` -------------------------------- ### Quick Start Example Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/javascript.md A basic example demonstrating how to initialize the PortalClient, generate a key handshake URL, and poll for user authentication. ```APIDOC ## Quick start ```typescript import { PortalClient } from 'portal-sdk'; const client = new PortalClient({ baseUrl: 'https://your-instance.hub.getportal.cc', authToken: 'your-auth-token', }); // Authenticate a user const op = await client.newKeyHandshakeUrl(); console.log('Share with user:', op.url); const result = await client.poll(op); console.log('User key:', result.main_key); ``` ``` -------------------------------- ### Install Protobuf Development Files on Fedora Source: https://github.com/portaltechnologiesinc/lib/blob/master/crates/portal-wallet/README.MD Run this command to install the necessary Google protobuf .proto files for tonic-build. ```bash sudo dnf install protobuf-devel ``` -------------------------------- ### HTTP API: Recurring (Subscription) Payment Setup Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Illustrates setting up a recurring payment subscription using the HTTP API. This example configures a monthly subscription with a maximum of 12 payments and an expiration time. Ensure the Authorization header is set. ```bash # HTTP — create monthly subscription capped at 12 payments curl -s -X POST http://localhost:3000/payments/recurring \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "main_key": "USER_PUBKEY_HEX", "subkeys": [], "payment_request": { "description": "Monthly subscription", "amount": 10000, "currency": "Millisats", "recurrence": { "calendar": "monthly", "first_payment_due": 1700000000, "max_payments": 12 }, "expires_at": 1700003600 } }' # → {"data":{"stream_id":"sub-abc"}} ``` -------------------------------- ### PortalApp Initialization and Listening Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/README.md Shows how to create a `PortalApp` instance using a `Keypair` and start listening for background tasks. ```APIDOC ## PortalApp Initialization and Listening ### Description Construct a `PortalApp` instance and start its background listening task. ### Usage ```ts const portalInstance = await PortalApp.create(keypair, ["wss://relay.nostr.net"]); portalInstance.listen(); // Notice the missing await here ``` ``` -------------------------------- ### Configure Environment Variables Source: https://github.com/portaltechnologiesinc/lib/blob/master/examples/README.md Copy the example environment file and fill in your Portal URL, token, and main key. ```bash PORTAL_URL=http://localhost:3000 PORTAL_TOKEN=your-secret-token MAIN_KEY=replace-with-user-pubkey-hex ``` -------------------------------- ### Portal SDK TypeScript Client Setup Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Installs the `portal-sdk` for Node.js. Demonstrates setting up `PortalClient` for manual polling, auto-polling with a specified interval, and webhook-based event handling. Includes universal error handling for `PortalSDKError` types. ```bash npm install portal-sdk ``` ```typescript import { PortalClient, PortalSDKError, Currency, Timestamp } from 'portal-sdk'; // --- Mode 1: Manual polling (default, no background timers) --- const client = new PortalClient({ baseUrl: 'http://localhost:3000', authToken: 'your-secret-token', debug: true, // optional: log HTTP calls to console }); // --- Mode 2: Auto-polling (background interval resolves op.done) --- const autoClient = new PortalClient({ baseUrl: 'http://localhost:3000', authToken: 'your-secret-token', autoPollingIntervalMs: 500, }); // Always call autoClient.destroy() when done to stop the interval. // --- Mode 3: Webhooks (portal-rest POSTs signed events to your server) --- const webhookClient = new PortalClient({ baseUrl: 'http://localhost:3000', authToken: 'your-secret-token', webhookSecret: 'hmac-signing-secret', }); // Universal error handling try { const ver = await client.version(); console.log(ver.version, ver.git_commit); } catch (err) { if (err instanceof PortalSDKError) { // codes: API_ERROR | NETWORK_ERROR | HTTP_ERROR | PARSE_ERROR | POLL_TIMEOUT console.error(err.code, err.message, err.statusCode); } } ``` -------------------------------- ### Run JavaScript Examples Source: https://github.com/portaltechnologiesinc/lib/blob/master/examples/README.md Execute the provided Node.js scripts to run various examples, such as authentication, single payments, and profile management. ```bash node auth.js node single-payment.js node profile.js ``` -------------------------------- ### Serve GitBook Locally Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Starts a local server to preview the GitBook documentation at http://localhost:4000. ```bash gitbook serve ``` -------------------------------- ### Install GitBook CLI Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Installs the legacy GitBook CLI globally using npm, required for local previewing of documentation. ```bash npm install -g @gitbook/cli ``` -------------------------------- ### PortalClient Setup Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Demonstrates how to instantiate the PortalClient with different configuration modes: manual polling, auto-polling, and webhooks. Includes universal error handling. ```APIDOC ## PortalClient Setup Install `portal-sdk` (Node.js 18+, server-side only). Three async-result modes: manual polling, auto-polling, or webhooks. ```bash npm install portal-sdk ``` ```typescript import { PortalClient, PortalSDKError, Currency, Timestamp } from 'portal-sdk'; // --- Mode 1: Manual polling (default, no background timers) --- const client = new PortalClient({ baseUrl: 'http://localhost:3000', authToken: 'your-secret-token', debug: true, // optional: log HTTP calls to console }); // --- Mode 2: Auto-polling (background interval resolves op.done) --- const autoClient = new PortalClient({ baseUrl: 'http://localhost:3000', authToken: 'your-secret-token', autoPollingIntervalMs: 500, }); // Always call autoClient.destroy() when done to stop the interval. // --- Mode 3: Webhooks (portal-rest POSTs signed events to your server) --- const webhookClient = new PortalClient({ baseUrl: 'http://localhost:3000', authToken: 'your-secret-token', webhookSecret: 'hmac-signing-secret', }); // Universal error handling try { const ver = await client.version(); console.log(ver.version, ver.git_commit); } catch (err) { if (err instanceof PortalSDKError) { // codes: API_ERROR | NETWORK_ERROR | HTTP_ERROR | PARSE_ERROR | POLL_TIMEOUT console.error(err.code, err.message, err.statusCode); } } ``` ``` -------------------------------- ### Async Operation: Authenticate Key Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/rest-api.md This example demonstrates the two-step process for asynchronous operations: starting the operation to get a stream ID, and then polling for events until completion. The 'authenticate-key' endpoint is used here as an example. ```bash # Step 1: start operation (example: authenticate a key) STREAM=$(curl -s -X POST $BASE_URL/authenticate-key \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{"main_key": "...", "subkeys": []}' \ | jq -r .stream_id) # Step 2: poll until done while true; do EVENTS=$(curl -s "$BASE_URL/events/$STREAM?after=0" \ -H "Authorization: Bearer $AUTH_TOKEN") echo $EVENTS | jq . # check if terminal event received, then break sleep 1 done ``` -------------------------------- ### Installation Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/javascript.md Install the portal-sdk package using npm. Requires Node.js 18+ and optionally TypeScript 4.5+. ```APIDOC ## Installation ```bash npm install portal-sdk ``` Requires Node.js 18+ and optionally TypeScript 4.5+. ``` -------------------------------- ### Serve mdBook Locally Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Navigates into the mdBook project directory and starts a local server to preview the documentation at http://localhost:3000. ```bash cd portal-docs mdbook serve ``` -------------------------------- ### Install mdBook Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Installs mdBook, a Rust-based documentation tool, using Cargo. ```bash cargo install mdbook ``` -------------------------------- ### Client Configuration Examples Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/java.md Shows different ways to configure the PortalClient, including manual polling, auto-polling, and webhook mode. ```APIDOC ## Configuration ```java // Manual polling (default) PortalClient client = new PortalClient( PortalClientConfig.create("http://localhost:3000", "your-auth-token") ); // Auto-polling every 2 seconds PortalClient client = new PortalClient( PortalClientConfig.create("http://localhost:3000", "your-auth-token") .autoPolling(2000) ); // Webhook mode PortalClient client = new PortalClient( PortalClientConfig.create("http://localhost:3000", "your-auth-token") .webhookSecret("your-webhook-secret") ); ``` ``` -------------------------------- ### Install GitBook Dependencies Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Installs necessary dependencies for GitBook within the docs directory. ```bash cd docs gitbook install ``` -------------------------------- ### Build TypeScript Client Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/building-from-source.md Navigate to the TypeScript client directory, install dependencies, and build the client. ```bash cd crates/portal-rest/clients/ts && npm install && npm run build ``` -------------------------------- ### Quick Start: Authenticate User Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/java.md Initialize the PortalClient and initiate a key handshake to authenticate a user. The generated URL should be shared with the user. ```java import cc.getportal.PortalClient; import cc.getportal.PortalClientConfig; PortalClient client = new PortalClient( PortalClientConfig.create("http://localhost:3000", "your-auth-token") ); // Authenticate a user var operation = client.newKeyHandshakeUrl(); System.out.println("Share with user: " + operation.url()); var result = client.pollUntilComplete(operation); System.out.println("User key: " + result.main_key()); ``` -------------------------------- ### Error Handling Example Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/javascript.md Example demonstrating how to catch and handle `PortalSDKError` exceptions. ```APIDOC ## Error Handling The SDK throws `PortalSDKError` with a `code` property: ```typescript import { PortalSDKError } from 'portal-sdk'; try { const { url } = await client.newKeyHandshakeUrl(); } catch (err) { if (err instanceof PortalSDKError) { console.error(err.code, err.message); } } ``` ``` -------------------------------- ### Minimal Setup with Environment Variables Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/environment-variables.md Run the portal-rest daemon with essential environment variables for authentication and Nostr private key. Generate a token using `openssl rand -hex 32` and convert nsec to hex with `nak decode`. ```bash PORTAL__AUTH__AUTH_TOKEN=dev-token \ PORTAL__NOSTR__PRIVATE_KEY=your-64-char-hex-key \ portal-rest ``` -------------------------------- ### Quick Start: Initialize Client and Authenticate User Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/javascript.md Initialize the PortalClient with your instance URL and authentication token. Then, generate a key handshake URL for user authentication and poll for the user's key. ```typescript import { PortalClient } from 'portal-sdk'; const client = new PortalClient({ baseUrl: 'https://your-instance.hub.getportal.cc', authToken: 'your-auth-token', }); // Authenticate a user const op = await client.newKeyHandshakeUrl(); console.log('Share with user:', op.url); const result = await client.poll(op); console.log('User key:', result.main_key); ``` -------------------------------- ### Docker Setup with Environment Variables Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/environment-variables.md Deploy the portal-rest SDK daemon using Docker, passing environment variables for authentication and Nostr private key. Alternatively, use a `.env` file, but do not commit it. ```bash docker run -d -p 3000:3000 \ -e PORTAL__AUTH__AUTH_TOKEN=my-secret-token \ -e PORTAL__NOSTR__PRIVATE_KEY=your-nostr-private-key-hex \ getportal/sdk-daemon:0.4.1 ``` -------------------------------- ### Install Portal SDK for TypeScript/JavaScript Source: https://github.com/portaltechnologiesinc/lib/blob/master/README.md Install the Portal SDK for TypeScript and JavaScript applications using npm. This is the primary SDK for web-based integrations. ```bash npm install portal-sdk ``` -------------------------------- ### Start Metro Bundler Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/example/README.md Run this command from the root of your React Native project to start the Metro JavaScript bundler. ```sh # Using npm npm start # OR using Yarn yarn start ``` -------------------------------- ### Troubleshoot Docker Container Startup Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/resources/troubleshooting.md Steps to diagnose and resolve issues with the Portal SDK daemon container not starting. This includes checking logs, environment variables, and image integrity, followed by removal and recreation. ```bash # Check logs docker logs portal-sdk-daemon ``` ```bash # Check environment variables docker inspect portal-sdk-daemon | grep -A 20 Env ``` ```bash # Verify Docker image docker images | grep portal ``` ```bash # Remove and recreate docker rm -f portal-sdk-daemon docker run -d --name portal-sdk-daemon \ -p 3000:3000 \ -e PORTAL__AUTH__AUTH_TOKEN=$PORTAL__AUTH__AUTH_TOKEN \ -e PORTAL__NOSTR__PRIVATE_KEY=$PORTAL__NOSTR__PRIVATE_KEY \ getportal/sdk-daemon:0.4.1 ``` -------------------------------- ### Run Portal SDK Daemon with Docker Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Quickest way to start the Portal REST daemon. Requires setting authentication and Nostr private keys via environment variables. Verify the daemon is running using the health and version endpoints. ```bash docker run -d -p 3000:3000 \ -e PORTAL__AUTH__AUTH_TOKEN=$(openssl rand -hex 32) \ -e PORTAL__NOSTR__PRIVATE_KEY=$(openssl rand -hex 32) \ getportal/sdk-daemon:0.4.1 ``` ```bash curl http://localhost:3000/health # → OK ``` ```bash curl http://localhost:3000/version # → {"data":{"version":"0.4.1","git_commit":"..."}} ``` -------------------------------- ### Initiate User Authentication Handshake (HTTP) Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/platform/getting-started.md Start the authentication process by requesting a handshake URL from the Portal API. This URL is then presented to the user. ```bash # Start the handshake — get a URL to show the user curl -s -X POST $BASE_URL/key-handshake \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{}' # → { "stream_id": "abc123", "url": "nostr+walletconnect://..." } # Show the URL to the user (QR code, link, etc.) # Then poll for the user's public key: curl -s "$BASE_URL/events/abc123?after=0" \ -H "Authorization: Bearer $AUTH_TOKEN" # → { "events": [{ "index": 0, "data": { "main_key": "USER_PUBKEY_HEX" } }] } ``` -------------------------------- ### Redeem Verification Proof (HTTP) Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/age-verification/integration-guide.md This HTTP example shows how to redeem a verification proof to prevent replay attacks. It requires the mint URL, unit, and the verification token. ```bash # Redeem the verification proof curl -s -X POST $BASE_URL/cashu/burn \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "mint_url": "https://mint.getportal.cc", "unit": "multi", "token": "VERIFICATION_TOKEN_HERE" }' ``` -------------------------------- ### Build and Run iOS App Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/example/README.md After installing CocoaPods dependencies, use this command to build and run the iOS application. ```sh # Using npm npm run ios # OR using Yarn yarn ios ``` -------------------------------- ### Setup Portal Client with Different Async Options Source: https://github.com/portaltechnologiesinc/lib/blob/master/crates/portal-rest/clients/ts/README.md Configure the PortalClient with options for manual polling, auto-polling, or webhooks to handle asynchronous results. ```typescript const client = new PortalClient({baseUrl: 'http://localhost:3000', authToken}); ``` ```typescript const client = new PortalClient({baseUrl, authToken, autoPollingIntervalMs: 500 }); // call client.destroy() to stop the scheduler when done ``` ```typescript const client = new PortalClient({baseUrl, authToken, webhookSecret: 'my-secret' }); ``` -------------------------------- ### Fetching User Profiles Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/platform/profiles.md This section provides examples for fetching user profiles using HTTP, JavaScript SDK, and Java SDK. ```APIDOC ## Fetching User Profiles (HTTP) ### Description Fetches a user profile from the Nostr network using their public key. ### Method GET ### Endpoint `/profile/USER_PUBKEY_HEX` ### Parameters #### Path Parameters - **USER_PUBKEY_HEX** (string) - Required - The hexadecimal public key of the user. #### Query Parameters None #### Request Body None ### Request Example ```bash curl -s $BASE_URL/profile/USER_PUBKEY_HEX \ -H "Authorization: Bearer $AUTH_TOKEN" ``` ### Response #### Success Response (200) - **name** (string) - Username (no spaces) - **display_name** (string) - Display name (can have spaces) - **picture** (string) - Profile picture URL - **about** (string) - Bio/description - **nip05** (string) - Nostr verified identifier (like email) #### Response Example ```json { "name": "alice", "display_name": "Alice", "picture": "https://...", "nip05": "alice@example.com", ... } ``` ``` ```APIDOC ## Fetching User Profiles (JavaScript SDK) ### Description Fetches a user profile using the `fetchProfile` method from the client SDK. ### Method SDK Method ### Endpoint N/A (SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript const profile = await client.fetchProfile(userPubkey); if (profile) { console.log('Name:', profile.name); console.log('Display Name:', profile.display_name); console.log('Picture:', profile.picture); console.log('About:', profile.about); console.log('NIP-05:', profile.nip05); } ``` ### Response #### Success Response - **profile** (object) - An object containing profile fields if found, otherwise null. - **name** (string) - Username (no spaces) - **display_name** (string) - Display name (can have spaces) - **picture** (string) - Profile picture URL - **about** (string) - Bio/description - **nip05** (string) - Nostr verified identifier (like email) #### Response Example (See console logs in the request example) ``` ```APIDOC ## Fetching User Profiles (Java SDK) ### Description Fetches a user profile using the `sendCommand` method with `FetchProfileRequest`. ### Method SDK Method ### Endpoint N/A (SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```java import cc.getportal.command.request.FetchProfileRequest; import cc.getportal.command.response.FetchProfileResponse; sdk.sendCommand( new FetchProfileRequest("user-pubkey-hex"), (res, err) -> { if (err != null) return; System.out.println("profile: " + res.profile()); } ); ``` ### Response #### Success Response - **res.profile()** (object) - An object containing profile fields. - **name** (string) - Username (no spaces) - **display_name** (string) - Display name (can have spaces) - **picture** (string) - Profile picture URL - **about** (string) - Bio/description - **nip05** (string) - Nostr verified identifier (like email) #### Response Example (See console output in the request example) ``` -------------------------------- ### Portal SDK Daemon Configuration File Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Example of a full configuration file for the Portal REST daemon, specifying listen port, Nostr relays, authentication token, Lightning network backend, database path, and webhook settings. Uncomment and configure the verification API key if needed. ```toml cat > ~/.portal-rest/config.toml <<'EOF' [info] listen_port = 3000 [nostr] private_key = "your-64-char-hex-key" relays = ["wss://relay.nostr.net", "wss://relay.damus.io", "wss://relay.getportal.cc"] [auth] auth_token = "your-secret-token" [wallet] ln_backend = "nwc" # "none" | "nwc" | "breez" [wallet.nwc] url = "nostr+walletconnect://..." [database] path = "portal-rest.db" [webhook] url = "https://yourserver.com/portal/webhook" secret = "hmac-signing-secret" # [verification] # api_key = "your-verification-api-key" # required for /verification/sessions EOF ``` -------------------------------- ### Request Recurring Payment Subscription (Java) Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/platform/recurring-payments.md Create a recurring payment subscription using the Java SDK. This example demonstrates setting up recurrence details and payment content, then sending the command asynchronously. ```java import cc.getportal.command.request.RequestRecurringPaymentRequest; import cc.getportal.command.response.RequestRecurringPaymentResponse; import cc.getportal.model.RecurringPaymentRequestContent; import cc.getportal.model.RecurrenceInfo; import cc.getportal.model.Currency; import java.util.List; RecurrenceInfo recurrence = new RecurrenceInfo( null, "monthly", null, System.currentTimeMillis() / 1000 ); RecurringPaymentRequestContent payment = new RecurringPaymentRequestContent( "Monthly sub", 10_000L, Currency.MILLISATS, null, recurrence, System.currentTimeMillis() / 1000 + 3600 ); sdk.sendCommand( new RequestRecurringPaymentRequest("user-pubkey-hex", List.of(), payment), (res, err) -> { if (err != null) { System.err.println(err); return; } System.out.println("recurring: " + res); } ); ``` -------------------------------- ### Create Static Token URL (Java SDK) Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/platform/static-tokens.md This Java example demonstrates how to generate a reusable authentication URL using a static token via the SDK. The `sendCommand` method is used with `KeyHandshakeUrlRequest`, and a callback handles the response, including the generated URL and potential errors. ```APIDOC ## sdk.sendCommand(request, callback) ### Description Sends a command to generate a reusable authentication URL using a static token. The callback processes the response, providing the URL or an error message. ### Parameters - **request** (KeyHandshakeUrlRequest) - An object containing the request details, including the static token. - **callback** (function) - A function that receives the `KeyHandshakeUrlResponse` and an error object. ### Request Example ```java import cc.getportal.command.request.KeyHandshakeUrlRequest; import cc.getportal.command.response.KeyHandshakeUrlResponse; import cc.getportal.command.notification.KeyHandshakeUrlNotification; sdk.sendCommand( new KeyHandshakeUrlRequest("my-static-token", null, (n) -> System.out.println("mainKey: " + n.main_key())), (res, err) -> { if (err != null) { System.err.println(err); return; } System.out.println("URL: " + res.url()); } ); ``` ``` -------------------------------- ### Create Static Token URL (JavaScript SDK) Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/platform/static-tokens.md This JavaScript example shows how to use the `newKeyHandshakeUrl` method from the SDK to generate a reusable authentication URL with a static token. The provided callback function will be invoked with the static token and main key for location-based authentication. ```APIDOC ## client.newKeyHandshakeUrl(callback, staticToken) ### Description Generates a reusable authentication URL using a static token. The callback function is executed with the main key and static token to handle location-specific authentication. ### Parameters - **callback** (function) - A function that receives `mainKey` and `preferredRelays`. - **staticToken** (string) - A token to make the auth URL reusable for a specific location or context. ### Request Example ```typescript const staticToken = 'table-14-restaurant-a'; const authUrl = await client.newKeyHandshakeUrl( (mainKey, preferredRelays) => { // mainKey + staticToken identify who and where handleLocationAuth(staticToken, mainKey); }, staticToken ); // Share authUrl (QR, NFC, link); it can be reused ``` ``` -------------------------------- ### Key Handshake and Authentication (HTTP) Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/platform/authentication.md Shows how to initiate a key handshake and authenticate a user's public key using cURL. This involves POSTing to `/key-handshake` to get a URL, then POSTing to `/authenticate-key` with the user's public key. Results are polled from the `/events` endpoint. ```bash # 1. Get a key handshake URL curl -s -X POST $BASE_URL/key-handshake \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{}' # → { "stream_id": "abc123", "url": "nostr+walletconnect://..." } # Show the URL to the user (QR code, link, etc.) # Poll the stream to receive the user's public key when they complete the handshake. # 2. Authenticate the key curl -s -X POST $BASE_URL/authenticate-key \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{"main_key": "USER_PUBKEY_HEX", "subkeys": []}' # → { "stream_id": "def456" } # 3. Poll for result curl -s "$BASE_URL/events/def456?after=0" \ -H "Authorization: Bearer $AUTH_TOKEN" # → { "events": [{ "index": 0, "type": "StatusUpdate", "data": { "status": "approved", "session_token": "..." } }] } ``` -------------------------------- ### Single Payment: Request and Poll Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/rest-api.md This example shows how to request a single payment and then poll for the payment status. The amount is specified in millisats. The response to polling includes the payment status and preimage if successful. ```bash # 1. Request payment (amount in millisats) curl -s -X POST $BASE_URL/payments/single \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "main_key": "USER_PUBKEY_HEX", "subkeys": [], "description": "Premium - 1 month", "amount": 10000, "currency": "millisats" }' # Response: { "stream_id": "xyz789" } # 2. Poll for result curl -s "$BASE_URL/events/xyz789?after=0" \ -H "Authorization: Bearer $AUTH_TOKEN" ``` ```json # Response: { "events": [{ "index": 0, "type": "StatusUpdate", "data": { "status": "paid", "preimage": "..." } }] } ``` -------------------------------- ### Initialize Portal App Session Source: https://github.com/portaltechnologiesinc/lib/blob/master/crates/portal-app-demo/src/index.html This function attempts to restore a user's session by checking local storage for credentials. If found, it tries to re-create the session via an API call. Otherwise, it proceeds to show a setup wizard. ```javascript async function init() { const savedNsec = localStorage.getItem('portal-nsec') const savedMnemonic = localStorage.getItem('portal-mnemonic') const savedPubkey = localStorage.getItem('portal-pubkey') const savedNpub = localStorage.getItem('portal-npub') if (savedPubkey && (savedNsec || savedMnemonic)) { // Re-create session const relaysJson = localStorage.getItem('portal-relays') const savedRelays = relaysJson ? JSON.parse(relaysJson) : ['wss://relay.damus.io'] const nwc = localStorage.getItem('portal-nwc') || null try { const body = { nsec: savedNsec || null, mnemonic: savedMnemonic || null, relays: savedRelays, nwc } const resp = await fetch('/api/session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) if (resp.ok) { const data = await resp.json() showDashboard(data.pubkey, data.pubkey_hex) return } } catch (e) { log('Reconnect failed: ' + e.message) } } // Show wizard: load default relays and sync key-mode panels await loadDefaultRelays() syncKeyModePanels() } init() ``` -------------------------------- ### Request Verification Token (HTTP) Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/age-verification/integration-guide.md This example demonstrates how to request a verification token from a Portal app user using an HTTP POST request. It requires the recipient's public key and returns a stream ID for polling. ```bash curl -s -X POST $BASE_URL/verification/token \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "recipient_key": "USER_PUBKEY_HEX", "subkeys": [] }' # → { "stream_id": "..." } # Poll events for the verification proof ``` -------------------------------- ### Set Up Development Environment Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/resources/contributing.md Set up the development environment using Nix for a recommended experience, or manually with Cargo. ```bash # Using Nix (recommended) nix develop ``` ```bash # Or manually with Cargo cargo build ``` -------------------------------- ### Async Operations Pattern Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/rest-api.md Explains the pattern for handling asynchronous operations: starting an operation to get a stream ID, and then polling for events until the operation completes. ```APIDOC ## Async Operations Pattern Most Portal operations (payments, auth, key handshake) are async — the user must approve in their wallet before a result is available. The pattern is always: 1. **Start the operation** → receive a `stream_id` 2. **Poll for events** until the operation completes ```bash # Step 1: start operation (example: authenticate a key) STREAM=$(curl -s -X POST $BASE_URL/authenticate-key \ -H "Authorization: Bearer $AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{"main_key": "...", "subkeys": []}' \ | jq -r .stream_id) # Step 2: poll until done while true; do EVENTS=$(curl -s "$BASE_URL/events/$STREAM?after=0" \ -H "Authorization: Bearer $AUTH_TOKEN") echo $EVENTS | jq . # check if terminal event received, then break sleep 1 done ``` ``` -------------------------------- ### Install CocoaPods Dependencies Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/example/README.md Before running the iOS app, install CocoaPods dependencies. Run 'bundle install' once to install the Ruby bundler, and 'bundle exec pod install' every time native dependencies are updated. ```sh bundle install ``` ```sh bundle exec pod install ``` -------------------------------- ### Run portal-app-demo Source: https://github.com/portaltechnologiesinc/lib/blob/master/crates/portal-app-demo/README.md Execute the portal-app-demo application from the command line. The app will create a default configuration file if one is not found. ```bash cargo run -p portal-app-demo ``` -------------------------------- ### Initialize mdBook Project Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Creates a new mdBook project named \'portal-docs\'. ```bash mdbook init portal-docs ``` -------------------------------- ### Install Specific SDK Version Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/resources/versioning.md Use this command to install a specific version of the TypeScript SDK via npm. ```bash npm install portal-sdk@0.4.1 ``` -------------------------------- ### Clone and Build Project Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/building-from-source.md Clone the repository and navigate into the project directory. ```bash git clone https://github.com/PortalTechnologiesInc/lib.git cd lib ``` -------------------------------- ### Install TypeScript and Configure tsconfig.json Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/resources/troubleshooting.md Install TypeScript as a development dependency and ensure essential compiler options like 'esModuleInterop' and 'skipLibCheck' are set in your tsconfig.json. ```bash npm install --save-dev typescript ``` ```json { "compilerOptions": { "esModuleInterop": true, "skipLibCheck": true } } ``` -------------------------------- ### Event Polling Response Example Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/rest-api.md This is an example of the JSON response structure when polling for events. It includes an array of events, each with an index, type, timestamp, and data. ```json { "events": [ { "index": 0, "type": "StatusUpdate", "timestamp": 1234567890, "data": { ... } } ] } ``` -------------------------------- ### Error Handling Example Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/java.md Illustrates how to check for errors in the response callback of `sendCommand`. ```APIDOC ## Error Handling Check the `err` parameter in each `sendCommand` callback: ```java sdk.sendCommand(someRequest, (response, err) -> { if (err != null) { System.err.println("Command failed: " + err); return; } // use response }); ``` ``` -------------------------------- ### Get Wallet Info (TypeScript SDK) Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Retrieves information about the user's wallet. ```APIDOC ## getWalletInfo() ### Description Retrieves information about the connected wallet, including its type and balance. ### Returns - An object containing wallet information. ### Example ```typescript const wallet = await client.getWalletInfo(); console.log(wallet.wallet_type, wallet.balance_msat, 'msat'); ``` ``` -------------------------------- ### Initialize Keypair and PortalApp Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/README.md Construct a Keypair from a mnemonic and initialize the PortalApp instance. Ensure `listen()` is called without `await` to run in the background. ```typescript const mnemonicObj = generateMnemonic(); const keypair = mnemonicObj.getKeypair(); const publicKey = keypair.publicKey(); const publicKeyString = publicKey.toString(); ``` ```typescript const portalInstance = await PortalApp.create(keypair, ["wss://relay.nostr.net"]); portalInstance.listen(); ``` -------------------------------- ### Build GitBook Static Site Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Generates a static version of the GitBook documentation, outputting to the \'_book/\' directory. ```bash gitbook build ``` -------------------------------- ### Poll for verification result Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/age-verification/api-reference.md Poll for verification events. Start with `after=0`, then use the last received `index + 1`. ```APIDOC ## Poll for verification result ### Description Poll for verification events. Start with `after=0`, then use the last received `index + 1`. ### Method GET ### Endpoint /events/{stream_id} ### Query Parameters - **after** (integer) - Required - The index after which to retrieve events. ### Response #### Success Response (200) - **events** (array) - A list of verification events. - **index** (integer) - The index of the event. - **type** (string) - The type of the event (e.g., "CashuResponse"). - **timestamp** (integer) - The Unix timestamp when the event occurred. - **data** (object) - The event data. - **status** (string) - The status of the verification ('success', 'rejected', 'insufficient_funds'). - **token** (string) - The verification proof (present if status is 'success'). - **reason** (string) - Details if the verification failed (present if status is 'rejected'). ### Response Example ```json { "events": [ { "index": 0, "type": "CashuResponse", "timestamp": 1234567890, "data": { "status": "success", "token": "cashuA..." } } ] } ``` ``` -------------------------------- ### Build mdBook Static Site Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Generates a static version of the mdBook documentation, outputting to the \'portal-docs/book/\' directory. ```bash mdbook build ``` -------------------------------- ### Fetching and Setting Profiles Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/README.md Illustrates how to fetch a user's profile using their public key and how to set or update a profile. ```APIDOC ## Fetching and Setting Profiles ### Description Fetch a user's profile by their public key and set or update the current user's profile. ### Usage ```ts const maybeProfile = await portalInstance.fetchProfile(publicKey); // Set a profile using this API. Note that all fields are optional and could be omitted await portalInstance.setProfile({ name: "Name", displayName: "Display Name", picture: "https://url-of-the-picture", nip05: "satoshi@getportal.cc", }); ``` ``` -------------------------------- ### Keypair Initialization Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/README.md Demonstrates how to generate or parse a mnemonic and obtain a Keypair object, which is essential for initializing the PortalApp. ```APIDOC ## Keypair Initialization ### Description Initialize a `Keypair` instance from a mnemonic to interact with the protocol. ### Usage ```ts // New random mnemonic const mnemonicObj = generateMnemonic(); // OR: Parse existing mnemonic const mnemonicObj = new Mnemonic("..."); const keypair = mnemonicObj.getKeypair(); const publicKey = keypair.publicKey(); const publicKeyString = publicKey.toString(); ``` ``` -------------------------------- ### Poll for Verification Result Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/age-verification/api-reference.md Poll the event stream for verification events. Start polling with `after=0` and increment the index with each subsequent request. ```http GET /events/{stream_id}?after={index} ``` ```json { "events": [ { "index": 0, "type": "CashuResponse", "timestamp": 1234567890, "data": { "status": "success", "token": "cashuA..." } } ] } ``` -------------------------------- ### Build and Run Custom Docker Image Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/docker-deployment.md Clone the repository, build a custom Docker image, and then run it. This method is useful for development or when using a specific branch. Remember to handle secrets securely and consider using a reverse proxy in production. ```bash git clone https://github.com/PortalTechnologiesInc/lib.git cd lib docker build -t portal-rest:latest . docker run -d -p 3000:3000 -e PORTAL__AUTH__AUTH_TOKEN=... -e PORTAL__NOSTR__PRIVATE_KEY=... portal-rest:latest ``` ```bash nix build .#rest-docker then docker load < result. ``` -------------------------------- ### Profile Lookup Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/sdk/rest-api.md Fetches a user's profile information using their public key. This is a simple GET request to the `/profile/{main_key}` endpoint. ```bash curl -s $BASE_URL/profile/USER_PUBKEY_HEX \ -H "Authorization: Bearer $AUTH_TOKEN" ``` -------------------------------- ### Java SDK: Full Authentication Flow Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Illustrates the authentication flow using the Java SDK, including setting up requests for key handshake URLs and authenticating keys. Error handling is included for asynchronous callbacks. ```java // Java SDK import cc.getportal.command.request.KeyHandshakeUrlRequest; import cc.getportal.command.request.AuthenticateKeyRequest; import java.util.List; sdk.sendCommand( new KeyHandshakeUrlRequest((n) -> { // n.main_key() is available when user completes handshake sdk.sendCommand( new AuthenticateKeyRequest(n.main_key(), List.of()), (res, err) -> { if (err != null) { System.err.println(err); return; } System.out.println("status: " + res.status()); } ); }), (res, err) -> { if (err != null) { System.err.println(err); return; } System.out.println("Handshake URL: " + res.url()); } ); ``` -------------------------------- ### Documentation File Structure Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/SETUP.md Illustrates the typical directory structure for project documentation. ```tree docs/ ├── README.md # Home page ├── SUMMARY.md # Table of contents ├── age-verification/ # Age verification guides ├── platform/ # Auth, payments, profiles ├── advanced/ # Self-hosting, deployment ├── sdk/ # SDK docs & API reference └── resources/ # FAQ, glossary, etc. ``` -------------------------------- ### Pull Cashu CDK Mint Docker Image Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/running-a-mint.md Pulls the latest Docker image for the Cashu CDK mint daemon. Ensure Docker is installed and running. ```bash docker pull getportal/cdk-mintd:latest ``` -------------------------------- ### Run Pre-built Docker Image Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/docker-deployment.md Execute the SDK daemon using a pre-built Docker image. Ensure to replace placeholder environment variables with your actual secrets. Pinning a specific version is recommended for production. ```bash docker run -d -p 3000:3000 \ -e PORTAL__AUTH__AUTH_TOKEN=your-secret-token \ -e PORTAL__NOSTR__PRIVATE_KEY=your-nostr-private-key-hex \ getportal/sdk-daemon:0.4.1 ``` -------------------------------- ### Get Wallet Information with TypeScript SDK Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Retrieves wallet details such as type and balance in msats using the Portal TypeScript SDK. This is useful for financial operations. ```typescript // Wallet info const wallet = await client.getWalletInfo(); console.log(wallet.wallet_type, wallet.balance_msat, 'msat'); ``` -------------------------------- ### Build CLI with Cargo Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/advanced/building-from-source.md Build the portal-cli package in release mode using Cargo. ```bash cargo build --package portal-cli --release ``` -------------------------------- ### Authenticate Key Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Initiates and completes the key authentication flow using the SDK. This involves getting a handshake URL, polling for user completion, and finally authenticating the key. ```APIDOC ## Authenticate Key Flow ### Description This flow covers the complete authentication process using a user's key. It involves obtaining a handshake URL, waiting for the user to complete the handshake, and then authenticating the key to obtain a session token. ### SDK Usage (TypeScript) ```typescript // TypeScript SDK — full auth flow const handshake = await client.newKeyHandshakeUrl(); console.log('Redirect or show QR:', handshake.url); // Wait for user to complete handshake const { main_key } = await client.poll(handshake, { timeoutMs: 120_000 }); // Now authenticate const authOp = await client.authenticateKey(main_key, []); const auth = await client.poll(authOp, { timeoutMs: 60_000 }); if (auth.status.status === 'approved') { console.log('Authenticated!'); console.log('Session token:', auth.status.session_token); console.log('Permissions:', auth.status.granted_permissions); } else { console.log('Declined. Reason:', auth.status.reason); } ``` ### SDK Usage (Java) ```java // Java SDK import cc.getportal.command.request.KeyHandshakeUrlRequest; import cc.getportal.command.request.AuthenticateKeyRequest; import java.util.List; sdk.sendCommand( new KeyHandshakeUrlRequest((n) -> { // n.main_key() is available when user completes handshake sdk.sendCommand( new AuthenticateKeyRequest(n.main_key(), List.of()), (res, err) -> { if (err != null) { System.err.println(err); return; } System.out.println("status: " + res.status()); } ); }), (res, err) -> { if (err != null) { System.err.println(err); return; } System.out.println("Handshake URL: " + res.url()); } ); ``` ``` -------------------------------- ### Verify NWC URL Format Source: https://github.com/portaltechnologiesinc/lib/blob/master/docs/resources/troubleshooting.md Check if the NWC URL is correctly formatted and starts with 'nostr+walletconnect://'. Test the NWC connection separately using a tool like Alby. ```bash # Verify NWC URL format (PORTAL__WALLET__NWC__URL) echo $PORTAL__WALLET__NWC__URL # Should start with: nostr+walletconnect:// ``` -------------------------------- ### Listening for Authentication Challenges Source: https://github.com/portaltechnologiesinc/lib/blob/master/react-native/README.md Details how to set up a listener for authentication challenges from the service. ```APIDOC ## Listening for Authentication Challenges ### Description Set up a listener to handle incoming authentication challenges. ### Usage ```ts class LocalAuthChallengeListener implements AuthChallengeListener { onAuthChallenge(event: AuthChallengeEvent): Promise { // Do something with the event. Return true/false to approve/reject the request return Promise.resolve(true); } } await portalInstance.listenForAuthChallenge(new LocalAuthChallengeListener()); ``` ``` -------------------------------- ### Calculate Next Occurrence with TypeScript SDK Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Calculates the next occurrence of a recurring event based on a frequency and a starting timestamp. Useful for billing or scheduling logic. Requires the 'Timestamp' utility. ```typescript // Calendar next-occurrence (for recurring billing logic) const next = await client.calculateNextOccurrence('monthly', Timestamp.fromNow(0)); console.log('Next monthly date:', next?.toDate().toISOString()); ``` -------------------------------- ### cURL: Fetch User Profile Source: https://context7.com/portaltechnologiesinc/lib/llms.txt Demonstrates how to fetch a user's Nostr profile (NIP-01 metadata) using their public key via a GET request to the `/profile/{main_key}` endpoint. ```bash # Fetch user profile curl -s "http://localhost:3000/profile/USER_PUBKEY_HEX" \ -H "Authorization: Bearer $AUTH_TOKEN" # → {"data":{"profile":{"id":"...","pubkey":"...","name":"alice","display_name":"Alice","picture":"https://...","nip05":"alice@example.com"}}} ```