Skip to content

Commit 45bb678

Browse files
authored
Merge pull request #1 from GetPayin-Tech/feat/iframe-init-option
feat: optional iframe init option for embedded checkout
2 parents 0a6a7ec + de9e18d commit 45bb678

8 files changed

Lines changed: 89 additions & 10 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project are documented here.
55
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
66
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.2.0]
9+
10+
### Added
11+
12+
- Optional `iframe` builder on `CreateInvoiceParams` (`.iframe(true)`) for embedded
13+
checkout. Like `payment_mode`, it is sent in the request body but excluded from the
14+
HMAC signature.
15+
816
## [0.1.0]
917

1018
### Added

‎README.md‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Ships a **Spring Boot starter** for one-line dependency injection.
3333
<dependency>
3434
<groupId>com.getpayin.paylink</groupId>
3535
<artifactId>paylink-core</artifactId>
36-
<version>0.1.0</version>
36+
<version>0.2.0</version>
3737
</dependency>
3838
```
3939

@@ -43,16 +43,16 @@ Spring Boot apps — use the starter instead (it pulls in the core):
4343
<dependency>
4444
<groupId>com.getpayin.paylink</groupId>
4545
<artifactId>paylink-spring-boot-starter</artifactId>
46-
<version>0.1.0</version>
46+
<version>0.2.0</version>
4747
</dependency>
4848
```
4949

5050
**Gradle**:
5151

5252
```groovy
53-
implementation 'com.getpayin.paylink:paylink-core:0.1.0'
53+
implementation 'com.getpayin.paylink:paylink-core:0.2.0'
5454
// or, for Spring Boot:
55-
implementation 'com.getpayin.paylink:paylink-spring-boot-starter:0.1.0'
55+
implementation 'com.getpayin.paylink:paylink-spring-boot-starter:0.2.0'
5656
```
5757

5858
## Quick start
@@ -78,6 +78,17 @@ CreateInvoiceResult checkout = paylink.invoices().create(
7878
response.sendRedirect(checkout.checkoutUrl());
7979
```
8080

81+
For an **embedded checkout**, pass `.iframe(true)` and render `checkout.checkoutUrl()`
82+
inside an `<iframe>` instead of redirecting:
83+
84+
```java
85+
CreateInvoiceResult checkout = paylink.invoices().create(
86+
new CreateInvoiceParams()
87+
.firstName("John").lastName("Doe").email("john@example.com")
88+
.orderTitle("Gold Plan").orderAmount("250.00").currency("USD")
89+
.iframe(true));
90+
```
91+
8192
Both credentials are issued in the PayLink dashboard under **Settings → Payment
8293
Integrations**. `publicToken` is sent on every request; `hashToken` is the secret used
8394
only to sign — it never leaves your server.

‎paylink-core/pom.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<groupId>com.getpayin.paylink</groupId>
99
<artifactId>paylink-parent</artifactId>
10-
<version>0.1.0</version>
10+
<version>0.2.0</version>
1111
</parent>
1212

1313
<artifactId>paylink-core</artifactId>

‎paylink-core/src/main/java/com/getpayin/paylink/internal/FieldOrders.java‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* The signed-field registry. Each entry lists a request's fields in the EXACT order
77
* the server concatenates them when it rebuilds the HMAC signature (the FormRequest
88
* {@code rules()} order, minus {@code token}/{@code signature}, and minus
9-
* {@code payment_mode} which is sent but not signed). Keep it in lockstep with the
9+
* unsigned fields such as {@code payment_mode} and {@code iframe} which are sent but not
10+
* signed). Keep it in lockstep with the
1011
* server FormRequests under {@code app/Http/Requests/Application/ExternalPaymentIntegration}.
1112
*/
1213
public final class FieldOrders {
@@ -30,7 +31,8 @@ private FieldOrders() {
3031
FieldSpec.of("redirection_url"),
3132
FieldSpec.of("webhook_url"),
3233
FieldSpec.of("order_details"),
33-
FieldSpec.unsigned("payment_mode")),
34+
FieldSpec.unsigned("payment_mode"),
35+
FieldSpec.unsigned("iframe")),
3436
false);
3537

3638
public static final EndpointSpec PAYMENT_VOID = new EndpointSpec(

‎paylink-core/src/main/java/com/getpayin/paylink/model/CreateInvoiceParams.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ public CreateInvoiceParams paymentMode(String value) {
8383
return this;
8484
}
8585

86+
public CreateInvoiceParams iframe(Boolean value) {
87+
fields.put("iframe", value);
88+
return this;
89+
}
90+
8691
/** Internal: the accumulated snake_case fields. */
8792
public Map<String, Object> fields() {
8893
return fields;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.getpayin.paylink;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import com.getpayin.paylink.internal.FieldOrders;
6+
import com.getpayin.paylink.internal.SignedBody;
7+
import com.getpayin.paylink.model.CreateInvoiceParams;
8+
import java.util.Map;
9+
import org.junit.jupiter.api.Test;
10+
11+
/**
12+
* The optional {@code iframe} field is sent in the body (coerced to {@code "1"}/{@code "0"})
13+
* but excluded from the HMAC signature, exactly like {@code payment_mode}.
14+
*/
15+
class IframeOptionTest {
16+
17+
private static final String PUBLIC_TOKEN = "pub_token";
18+
private static final String HASH_TOKEN = "test_hash_token_abc123";
19+
20+
private static CreateInvoiceParams baseParams() {
21+
return new CreateInvoiceParams()
22+
.firstName("John").lastName("Doe").email("john@example.com")
23+
.orderTitle("Gold Plan").orderAmount("250.00").currency("USD");
24+
}
25+
26+
@Test
27+
void iframeTrueSerializesToOneInBody() {
28+
Map<String, String> body = SignedBody.build(
29+
FieldOrders.INVOICE_CREATE, baseParams().iframe(true).fields(), PUBLIC_TOKEN, HASH_TOKEN);
30+
31+
assertEquals("1", body.get("iframe"));
32+
}
33+
34+
@Test
35+
void iframeFalseSerializesToZeroInBody() {
36+
Map<String, String> body = SignedBody.build(
37+
FieldOrders.INVOICE_CREATE, baseParams().iframe(false).fields(), PUBLIC_TOKEN, HASH_TOKEN);
38+
39+
assertEquals("0", body.get("iframe"));
40+
}
41+
42+
@Test
43+
void iframeIsUnsignedSoItDoesNotChangeTheSignature() {
44+
Map<String, String> without = SignedBody.build(
45+
FieldOrders.INVOICE_CREATE, baseParams().fields(), PUBLIC_TOKEN, HASH_TOKEN);
46+
Map<String, String> with = SignedBody.build(
47+
FieldOrders.INVOICE_CREATE, baseParams().iframe(true).fields(), PUBLIC_TOKEN, HASH_TOKEN);
48+
49+
// iframe is present in the body but must not affect the HMAC signature.
50+
assertEquals("1", with.get("iframe"));
51+
assertEquals(without.get("signature"), with.get("signature"));
52+
}
53+
}

‎paylink-spring-boot-starter/pom.xml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<groupId>com.getpayin.paylink</groupId>
99
<artifactId>paylink-parent</artifactId>
10-
<version>0.1.0</version>
10+
<version>0.2.0</version>
1111
</parent>
1212

1313
<artifactId>paylink-spring-boot-starter</artifactId>
@@ -18,7 +18,7 @@
1818
<dependency>
1919
<groupId>com.getpayin.paylink</groupId>
2020
<artifactId>paylink-core</artifactId>
21-
<version>0.1.0</version>
21+
<version>0.2.0</version>
2222
</dependency>
2323

2424
<dependency>

‎pom.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.getpayin.paylink</groupId>
88
<artifactId>paylink-parent</artifactId>
9-
<version>0.1.0</version>
9+
<version>0.2.0</version>
1010
<packaging>pom</packaging>
1111

1212
<name>PayLink Java SDK (parent)</name>

0 commit comments

Comments
 (0)