();
var client = MonetaClient.builder()
.baseUri(base)
@@ -889,9 +917,14 @@ void namesEachCallByItsTemplateWithoutTheAccountIdOrTheQuery() {
client.accounts(TOKEN);
client.balance(TOKEN, "acc-1");
client.transactions(TOKEN, "acc-1", FROM, TO);
+ client.tokenExpiry(TOKEN);
assertEquals(
- List.of(ACCOUNTS, ACCOUNTS + "/{accountId}/balance", ACCOUNTS + "/{accountId}/transactions"),
+ List.of(
+ ACCOUNTS,
+ ACCOUNTS + "/{accountId}/balance",
+ ACCOUNTS + "/{accountId}/transactions",
+ TOKEN_INTROSPECT),
templates.stream().distinct().toList());
}
diff --git a/modules/moneta-api/src/test/resources/moneta/README.md b/modules/moneta-api/src/test/resources/moneta/README.md
index 10a2cc4..fbeee73 100644
--- a/modules/moneta-api/src/test/resources/moneta/README.md
+++ b/modules/moneta-api/src/test/resources/moneta/README.md
@@ -1,9 +1,11 @@
# Test responses
-Two kinds, told apart by the folder:
+Three kinds:
- **`live/`** — recorded from the live API, then anonymised. The shape is MONETA's own; every identifying value
is replaced as below.
+- **`token-introspect.json`**: the example from MONETA's specification (VipTokenIntrospect_v1), kept as it is:
+ MONETA's own shape, and it names nobody.
- **The rest** — written by hand in the shape the only public client (a PHP package) assumes, before anything
was recorded. Replace each with a recorded one as the live API shows it.
diff --git a/modules/moneta-api/src/test/resources/moneta/token-introspect.json b/modules/moneta-api/src/test/resources/moneta/token-introspect.json
new file mode 100644
index 0000000..f654b7c
--- /dev/null
+++ b/modules/moneta-api/src/test/resources/moneta/token-introspect.json
@@ -0,0 +1 @@
+{"expiration": "2026-03-06T11:38:09+01:00"}
diff --git a/testing/native/src/main/java/example/nativeimage/NativeCaller.java b/testing/native/src/main/java/example/nativeimage/NativeCaller.java
index 2268bc3..818be43 100644
--- a/testing/native/src/main/java/example/nativeimage/NativeCaller.java
+++ b/testing/native/src/main/java/example/nativeimage/NativeCaller.java
@@ -12,9 +12,9 @@
import java.time.LocalDate;
/**
- * Reads accounts, a balance and transactions from a fake MONETA serving the client's test fixtures, and prints
- * what the client returned. bin/native-test.sh runs it on the JVM and as a native image and compares the two: a
- * record the image cannot bind fails the call, and a component it cannot see prints as null.
+ * Reads accounts, a balance, transactions and the token's expiry from a fake MONETA serving the client's test
+ * fixtures, and prints what the client returned. bin/native-test.sh runs it on the JVM and as a native image and
+ * compares the two: a record the image cannot bind fails the call, and a component it cannot see prints as null.
*
* Usage: {@code NativeCaller
}
*/
@@ -28,6 +28,8 @@ public static void main(String[] args) throws IOException {
serve(server, ACCOUNTS, fixtures.resolve("accounts.json"));
serve(server, ACCOUNTS + "/acc-1/balance", fixtures.resolve("live/balance.json"));
serve(server, ACCOUNTS + "/acc-1/transactions", fixtures.resolve("live/booked.json"));
+ // The only record whose java.time component Jackson binds itself rather than a String parsed after.
+ serve(server, "/api/v1/vip/token/introspect", fixtures.resolve("token-introspect.json"));
server.start();
var address = server.getAddress();
var base = URI.create("http://" + address.getHostString() + ":" + address.getPort() + "/");
@@ -37,6 +39,7 @@ public static void main(String[] args) throws IOException {
System.out.println(moneta.balance(token, "acc-1"));
moneta.transactions(token, "acc-1", LocalDate.of(2026, 8, 1), LocalDate.of(2026, 8, 31))
.forEach(System.out::println);
+ System.out.println(moneta.tokenExpiry(token));
} finally {
server.stop(0);
}
diff --git a/tools/peek/src/main/java/peek/Peek.java b/tools/peek/src/main/java/peek/Peek.java
index 49d9985..33f712b 100644
--- a/tools/peek/src/main/java/peek/Peek.java
+++ b/tools/peek/src/main/java/peek/Peek.java
@@ -57,8 +57,9 @@ public static void main(String[] args) throws IOException {
}
}
}
+ case "token" -> System.out.println("expires " + moneta.tokenExpiry(access));
case "record" -> record(moneta, access, arguments);
- default -> fail("unknown command " + command + "; accounts, balance, transactions or record");
+ default -> fail("unknown command " + command + "; accounts, balance, token, transactions or record");
}
}
}