|
1 | | -# Portal Java SDK - Documentation |
| 1 | +# Portal Java SDK |
2 | 2 |
|
3 | | -## Introduction |
4 | | - |
5 | | -A Java client for the Portal WebSocket Server, providing Nostr-based authentication and Lightning Network payment processing capabilities. |
6 | | - |
7 | | ---- |
| 3 | +Java 17 SDK for the [Portal REST API](https://github.com/PortalTechnologiesInc/lib). |
8 | 4 |
|
9 | 5 | ## Installation |
10 | 6 |
|
11 | | -1. Add the Jitpack repository to your `build.gradle`: |
12 | | - ```groovy |
13 | | - repositories { |
14 | | - maven { url 'https://jitpack.io' } |
15 | | - } |
16 | | - ``` |
17 | | - |
18 | | - Or if you are using Maven, add the following to your `pom.xml`: |
19 | | - ```xml |
20 | | - <repository> |
21 | | - <id>jitpack.io</id> |
22 | | - <url>https://jitpack.io</url> |
23 | | - </repository> |
24 | | - ``` |
25 | | - |
26 | | -2. Add the dependency to your `build.gradle`: |
27 | | - ```groovy |
28 | | - dependencies { |
29 | | - implementation 'com.github.PortalTechnologiesInc:java-sdk:0.3.0' |
30 | | - } |
31 | | - ``` |
32 | | - |
33 | | - Or if you are using Maven, add the following to your `pom.xml`: |
34 | | - ```xml |
35 | | - <dependency> |
36 | | - <groupId>com.github.PortalTechnologiesInc</groupId> |
37 | | - <artifactId>java-sdk</artifactId> |
38 | | - <version>0.3.0</version> |
39 | | - </dependency> |
40 | | - ``` |
41 | | - |
42 | | -3. Once you're done, you may now proceed integrating the SDK into your project. |
43 | | - |
44 | | ---- |
45 | | - |
46 | | -## Versioning & Compatibility |
47 | | - |
48 | | -The Java SDK version is kept in sync with the [Portal SDK Daemon](https://hub.docker.com/r/getportal/sdk-daemon) (`getportal/sdk-daemon`). |
49 | | - |
50 | | -**Compatibility rule:** the `major.minor` version of the SDK must match the `major.minor` version of the SDK Daemon. The patch version (`x` in `0.3.x`) is independent and can differ — it only contains bug fixes. |
51 | | - |
52 | | -| SDK version | SDK Daemon version | |
53 | | -|-------------|-------------------| |
54 | | -| `0.3.x` | `0.3.x` | |
55 | | - |
56 | | -**Example:** SDK `0.3.0` works with `getportal/sdk-daemon:0.3.1`, but not with `getportal/sdk-daemon:0.4.0`. |
57 | | - |
58 | | -When upgrading to a new `major.minor`, update both the SDK dependency and the Docker image tag together. |
| 7 | +```kotlin |
| 8 | +// settings.gradle.kts |
| 9 | +dependencyResolutionManagement { |
| 10 | + repositories { maven { url = uri("https://jitpack.io") } } |
| 11 | +} |
59 | 12 |
|
60 | | - |
61 | | ---- |
62 | | - |
63 | | -## Basic Usage |
64 | | - |
65 | | -### Initialization |
66 | | - |
67 | | -Create an instance of `PortalSDK` by passing the websocket endpoint of your portal server: |
68 | | - |
69 | | -```java |
70 | | -var portalSDK = new PortalSDK(wsEndpoint); |
| 13 | +// build.gradle.kts |
| 14 | +dependencies { |
| 15 | + implementation("com.github.PortalTechnologiesInc:java-sdk:0.4.0") |
| 16 | +} |
71 | 17 | ``` |
72 | 18 |
|
73 | | -### Connecting to the server |
| 19 | +## Setup |
74 | 20 |
|
75 | | -Establish the WebSocket connection, then authenticate with your token: |
| 21 | +Choose how you want to receive async results: |
76 | 22 |
|
77 | 23 | ```java |
78 | | -portalSDK.connect(); |
79 | | -portalSDK.authenticate(authToken); |
| 24 | +// Manual polling — you call pollUntilComplete() yourself, no background threads |
| 25 | +PortalClient client = new PortalClient( |
| 26 | + PortalClientConfig.create("http://localhost:3000", "token") |
| 27 | +); |
| 28 | + |
| 29 | +// Auto-polling — background scheduler, just use done() |
| 30 | +PortalClient client = new PortalClient( |
| 31 | + PortalClientConfig.create("http://localhost:3000", "token") |
| 32 | + .autoPolling(500) // poll every 500ms |
| 33 | +); |
| 34 | + |
| 35 | +// Webhooks — portal-rest POSTs to your server, just use done() |
| 36 | +PortalClient client = new PortalClient( |
| 37 | + PortalClientConfig.create("http://localhost:3000", "token") |
| 38 | + .webhookSecret("my-secret") |
| 39 | +); |
80 | 40 | ``` |
81 | 41 |
|
| 42 | +## Async operations |
82 | 43 |
|
83 | | -### Sending a command |
| 44 | +All async methods return `AsyncOperation<T>` with `streamId` (available immediately) |
| 45 | +and `done` (`CompletableFuture<T>` that resolves when the operation completes). |
84 | 46 |
|
85 | | -You can send a command to the server by calling the `sendCommand` method. |
| 47 | +### Manual polling |
86 | 48 |
|
87 | 49 | ```java |
88 | | -portalSDK.sendCommand(request, (response, err) -> { |
89 | | - if(err != null) { |
90 | | - logger.error("error sending command: {}", err); |
91 | | - return; |
92 | | - } |
93 | | - logger.info("command sent successfully: {}", response); |
94 | | -}); |
| 50 | +AsyncOperation<InvoiceStatus> op = client.requestSinglePayment( |
| 51 | + mainKey, List.of(), |
| 52 | + new SinglePaymentRequestContent("Coffee", 1000, Currency.MILLISATS, null, null, null) |
| 53 | +); |
| 54 | + |
| 55 | +// blocks until paid/rejected/timeout |
| 56 | +InvoiceStatus result = client.pollUntilComplete(op, PollOptions.defaults().timeoutMs(60_000)); |
| 57 | +System.out.println(result.status); // "paid", "timeout", "user_rejected", ... |
95 | 58 | ``` |
96 | 59 |
|
97 | | -### Basic example |
| 60 | +### Auto-polling |
98 | 61 |
|
99 | 62 | ```java |
100 | | -portalSDK.sendCommand(new CalculateNextOccurrenceRequest("weekly", System.currentTimeMillis() / 1000), (res, err) -> { |
101 | | - if(err != null) { |
102 | | - logger.error("error calculating next occurrence: {}", err); |
103 | | - return; |
104 | | - } |
105 | | - logger.info("next occurrence: {}", res.next_occurrence()); |
106 | | -}); |
| 63 | +// client configured with .autoPolling(500) |
| 64 | +AsyncOperation<InvoiceStatus> op = client.requestSinglePayment(...); |
| 65 | +op.done().thenAccept(result -> System.out.println(result.status)); |
107 | 66 | ``` |
108 | | ---- |
109 | | - |
110 | | -## Available Commands |
111 | 67 |
|
112 | | -Commands are implemented as specific request classes in [`src/main/java/cc/getportal/command/request/`](./src/main/java/cc/getportal/command/request/), and used via the `sendCommand()` method of the [`PortalSDK`](./src/main/java/cc/getportal/PortalSDK.java) class. |
| 68 | +### Webhooks |
113 | 69 |
|
114 | | -Some key available commands include: |
115 | | - |
116 | | -- [`AuthRequest`](./src/main/java/cc/getportal/command/request/AuthRequest.java): Authenticate using a token. |
117 | | -- [`KeyHandshakeUrlRequest`](./src/main/java/cc/getportal/command/request/KeyHandshakeUrlRequest.java): Get handshake URL for key and relays. |
118 | | -- [`RequestSinglePaymentRequest`](./src/main/java/cc/getportal/command/request/RequestSinglePaymentRequest.java): Request a single payment. |
119 | | -- [`MintCashuRequest`](./src/main/java/cc/getportal/command/request/MintCashuRequest.java): Mint Cashu tokens. |
120 | | - |
121 | | -> See [`src/main/java/cc/getportal/command/request/`](./src/main/java/cc/getportal/command/request/) for all available commands and additional details. |
122 | | -
|
123 | | -To use a command, instantiate its request class and pass it to `PortalSDK.sendCommand(...)`. The full list of commands may evolve; check the request folder for the latest options. |
124 | | - |
125 | | ---- |
| 70 | +```java |
| 71 | +// client configured with .webhookSecret("my-secret") |
| 72 | +AsyncOperation<InvoiceStatus> op = client.requestSinglePayment(...); |
| 73 | +op.done().thenAccept(result -> System.out.println(result.status)); |
126 | 74 |
|
127 | | -## Example Integrations |
| 75 | +// in your HTTP server's POST /webhook handler: |
| 76 | +client.deliverWebhookPayload(rawBody, request.getHeader("X-Portal-Signature")); |
| 77 | +``` |
128 | 78 |
|
129 | | -- See [portal-demo](https://github.com/PortalTechnologiesInc/portal-demo) for a Kotlin example. |
| 79 | +## Async methods |
130 | 80 |
|
131 | | ---- |
| 81 | +| Method | Resolves to | |
| 82 | +|--------|-------------| |
| 83 | +| `requestSinglePayment(mainKey, subkeys, content)` | `AsyncOperation<InvoiceStatus>` | |
| 84 | +| `requestPaymentRaw(mainKey, subkeys, content)` | `AsyncOperation<InvoiceStatus>` | |
| 85 | +| `requestRecurringPayment(mainKey, subkeys, content)` | `AsyncOperation<RecurringPaymentResponseContent>` | |
| 86 | +| `requestInvoice(recipientKey, subkeys, params)` | `AsyncOperation<InvoicePaymentResponse>` | |
| 87 | +| `requestCashu(recipientKey, subkeys, mintUrl, unit, amount)` | `AsyncOperation<CashuResponseStatus>` | |
| 88 | +| `authenticateKey(mainKey, subkeys)` | `AsyncOperation<AuthResponseData>` | |
| 89 | +| `newKeyHandshakeUrl(staticToken, noRequest)` | `AsyncOperation<KeyHandshakeResult>` | |
132 | 90 |
|
133 | | -## Main API |
| 91 | +## Sync methods |
134 | 92 |
|
135 | | -- `PortalSDK` - Main client class |
136 | | -- `PortalRequest` - Represents a request to the server |
137 | | -- `PortalResponse` - Represents a response from the server |
138 | | -- `PortalNotification` - Represents a notification from the server |
| 93 | +`health()`, `version()`, `info()`, `fetchProfile()`, `payInvoice()`, |
| 94 | +`closeRecurringPayment()`, `issueJwt()`, `verifyJwt()`, `addRelay()`, `removeRelay()`, |
| 95 | +`mintCashu()`, `burnCashu()`, `sendCashuDirect()`, `calculateNextOccurrence()`, |
| 96 | +`fetchNip05Profile()`, `getWalletInfo()` |
139 | 97 |
|
140 | | ---- |
| 98 | +## Versioning |
141 | 99 |
|
142 | | -## Support |
| 100 | +Java SDK `major.minor` must match the portal-rest (sdk-daemon) version. |
143 | 101 |
|
144 | | -For questions or issues, see the official documentation or open an issue on the project's GitHub repository. |
| 102 | +| Java SDK | sdk-daemon | |
| 103 | +|----------|------------| |
| 104 | +| 0.4.x | 0.4.x | |
| 105 | +| 0.3.x | 0.3.x | |
0 commit comments