From 3dc7d3f2903edec88f307dfa5d17e6b5f377e3f0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:10:14 +0000 Subject: [PATCH 01/33] chore: configure new SDK language --- .stats.yml | 2 +- README.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index ddb484b7..44b43de3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-4ecc06edca2cfad4eaf11573611e89823fda5f56370bac5cd02a498a6b277d09.yml openapi_spec_hash: 8f4a30bec4348cbde85b1e65bef9189a -config_hash: 9dddee5f7af579864599849cb28a0770 +config_hash: 751a4cc75aa0276b40cc2c7879b24dea diff --git a/README.md b/README.md index 234c6d0f..e6493697 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,15 @@ The Lithic Java SDK provides convenient access to the [Lithic REST API](https:// The Lithic Java SDK is similar to the Lithic Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions. +## MCP Server + +Use the Lithic MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. + +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=lithic-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImxpdGhpYy1tY3AiXX0) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22lithic-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22lithic-mcp%22%5D%7D) + +> Note: You may need to set environment variables in your MCP client. + The REST API documentation can be found on [docs.lithic.com](https://docs.lithic.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.lithic.api/lithic-java/0.115.0). From 6b3f7ee38b9f387e28cce9d19d5fec3a6718cfbf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 22:34:58 +0000 Subject: [PATCH 02/33] chore(internal): codegen related update --- .../api/client/okhttp/LithicOkHttpClient.kt | 22 +++++++++++++++++++ .../client/okhttp/LithicOkHttpClientAsync.kt | 22 +++++++++++++++++++ .../lithic/api/client/okhttp/OkHttpClient.kt | 9 ++++++++ 3 files changed, 53 insertions(+) diff --git a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClient.kt b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClient.kt index 1eb00e26..ac00e64a 100644 --- a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClient.kt +++ b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClient.kt @@ -18,6 +18,7 @@ import java.time.Clock import java.time.Duration import java.util.Optional import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -46,11 +47,31 @@ class LithicOkHttpClient private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -323,6 +344,7 @@ class LithicOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClientAsync.kt b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClientAsync.kt index 0f0acb3e..aebe796e 100644 --- a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClientAsync.kt +++ b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/LithicOkHttpClientAsync.kt @@ -18,6 +18,7 @@ import java.time.Clock import java.time.Duration import java.util.Optional import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -46,11 +47,31 @@ class LithicOkHttpClientAsync private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -323,6 +344,7 @@ class LithicOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt index 1b37107b..1417591d 100644 --- a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt +++ b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt @@ -15,11 +15,13 @@ import java.net.Proxy import java.time.Duration import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Call import okhttp3.Callback +import okhttp3.Dispatcher import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType @@ -198,6 +200,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var dispatcherExecutorService: ExecutorService? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -208,6 +211,10 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { this.sslSocketFactory = sslSocketFactory } @@ -229,6 +236,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien .callTimeout(timeout.request()) .proxy(proxy) .apply { + dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } + val sslSocketFactory = sslSocketFactory val trustManager = trustManager if (sslSocketFactory != null && trustManager != null) { From da510920d18bdd6b4e2a655755e9fe21f145bf9f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 23:03:56 +0000 Subject: [PATCH 03/33] chore(internal): support uploading Maven repo artifacts to stainless package server --- .github/workflows/ci.yml | 18 ++++ .../src/main/kotlin/lithic.publish.gradle.kts | 17 +++- scripts/upload-artifacts | 96 +++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) create mode 100755 scripts/upload-artifacts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6e0ed7d..e3fe4992 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,9 @@ jobs: build: timeout-minutes: 15 name: build + permissions: + contents: read + id-token: write runs-on: ${{ github.repository == 'stainless-sdks/lithic-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork @@ -61,6 +64,21 @@ jobs: - name: Build SDK run: ./scripts/build + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/lithic-java' + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Build and upload Maven artifacts + if: github.repository == 'stainless-sdks/lithic-java' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + PROJECT: lithic-java + run: ./scripts/upload-artifacts test: timeout-minutes: 15 name: test diff --git a/buildSrc/src/main/kotlin/lithic.publish.gradle.kts b/buildSrc/src/main/kotlin/lithic.publish.gradle.kts index e5ca4e7e..bda852fe 100644 --- a/buildSrc/src/main/kotlin/lithic.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/lithic.publish.gradle.kts @@ -7,6 +7,17 @@ plugins { id("com.vanniktech.maven.publish") } +publishing { + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } +} + repositories { gradlePluginPortal() mavenCentral() @@ -17,8 +28,10 @@ extra["signingInMemoryKeyId"] = System.getenv("GPG_SIGNING_KEY_ID") extra["signingInMemoryKeyPassword"] = System.getenv("GPG_SIGNING_PASSWORD") configure { - signAllPublications() - publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + if (!project.hasProperty("publishLocal")) { + signAllPublications() + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + } coordinates(project.group.toString(), project.name, project.version.toString()) configure( diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts new file mode 100755 index 00000000..729e6f22 --- /dev/null +++ b/scripts/upload-artifacts @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# ANSI Color Codes +GREEN='\033[32m' +RED='\033[31m' +NC='\033[0m' # No Color + +log_error() { + local msg="$1" + local headers="$2" + local body="$3" + echo -e "${RED}${msg}${NC}" + [[ -f "$headers" ]] && echo -e "${RED}Headers:$(cat "$headers")${NC}" + echo -e "${RED}Body: ${body}${NC}" + exit 1 +} + +upload_file() { + local file_name="$1" + local tmp_headers + tmp_headers=$(mktemp) + + if [ -f "$file_name" ]; then + echo -e "${GREEN}Processing file: $file_name${NC}" + pkg_file_name="mvn${file_name#./build/local-maven-repo}" + + # Get signed URL for uploading artifact file + signed_url_response=$(curl -X POST -G "$URL" \ + -sS --retry 5 \ + -D "$tmp_headers" \ + --data-urlencode "filename=$pkg_file_name" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + + # Validate JSON and extract URL + if ! signed_url=$(echo "$signed_url_response" | jq -e -r '.url' 2>/dev/null) || [[ "$signed_url" == "null" ]]; then + log_error "Failed to get valid signed URL" "$tmp_headers" "$signed_url_response" + fi + + # Set content-type based on file extension + local extension="${file_name##*.}" + local content_type + case "$extension" in + jar) content_type="application/java-archive" ;; + md5|sha1|sha256|sha512) content_type="text/plain" ;; + module) content_type="application/json" ;; + pom|xml) content_type="application/xml" ;; + *) content_type="application/octet-stream" ;; + esac + + # Upload file + upload_response=$(curl -v -X PUT \ + --retry 5 \ + -D "$tmp_headers" \ + -H "Content-Type: $content_type" \ + --data-binary "@${file_name}" "$signed_url" 2>&1) + + if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then + log_error "Failed upload artifact file" "$tmp_headers" "$upload_response" + fi + + # Insert small throttle to reduce rate limiting risk + sleep 0.1 + fi +} + +walk_tree() { + local current_dir="$1" + + for entry in "$current_dir"/*; do + # Check that entry is valid + [ -e "$entry" ] || [ -h "$entry" ] || continue + + if [ -d "$entry" ]; then + walk_tree "$entry" + else + upload_file "$entry" + fi + done +} + +cd "$(dirname "$0")/.." + +echo "::group::Creating local Maven content" +./gradlew publishMavenPublicationToLocalFileSystemRepository -PpublishLocal +echo "::endgroup::" + +echo "::group::Uploading to pkg.stainless.com" +walk_tree "./build/local-maven-repo" +echo "::endgroup::" + +echo "::group::Generating instructions" +echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" +echo "::endgroup::" From 6122eccf30d48db7aaba2fd6f8e94bf76fc7ceb4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 11:15:57 +0000 Subject: [PATCH 04/33] feat(api): make filter optional for Spend Velocity Auth Rules fix(api): rename WIRE_DRAWDOWN_REQUEST to WIRE_INBOUND_DRAWDOWN_REQUEST --- .stats.yml | 6 +- README.md | 9 - .../kotlin/com/lithic/api/models/Payment.kt | 10 +- .../lithic/api/models/VelocityLimitParams.kt | 342 +++++++++--------- .../api/models/VelocityLimitParamsTest.kt | 48 +-- 5 files changed, 202 insertions(+), 213 deletions(-) diff --git a/.stats.yml b/.stats.yml index 44b43de3..ac611e10 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-4ecc06edca2cfad4eaf11573611e89823fda5f56370bac5cd02a498a6b277d09.yml -openapi_spec_hash: 8f4a30bec4348cbde85b1e65bef9189a -config_hash: 751a4cc75aa0276b40cc2c7879b24dea +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-c06c4d54858775fef1de57e33d471e997cb28fe0c925fd7b08ba45fdd335e938.yml +openapi_spec_hash: 23745357b2171bcdfb5d30bfef1df48d +config_hash: 9dddee5f7af579864599849cb28a0770 diff --git a/README.md b/README.md index e6493697..234c6d0f 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,6 @@ The Lithic Java SDK provides convenient access to the [Lithic REST API](https:// The Lithic Java SDK is similar to the Lithic Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions. -## MCP Server - -Use the Lithic MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. - -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=lithic-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImxpdGhpYy1tY3AiXX0) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22lithic-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22lithic-mcp%22%5D%7D) - -> Note: You may need to set environment variables in your MCP client. - The REST API documentation can be found on [docs.lithic.com](https://docs.lithic.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.lithic.api/lithic-java/0.115.0). diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Payment.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Payment.kt index 5927991a..f1079776 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Payment.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Payment.kt @@ -4769,7 +4769,7 @@ private constructor( @JvmField val WIRE_OUTBOUND_ADMIN = of("WIRE_OUTBOUND_ADMIN") - @JvmField val WIRE_DRAWDOWN_REQUEST = of("WIRE_DRAWDOWN_REQUEST") + @JvmField val WIRE_INBOUND_DRAWDOWN_REQUEST = of("WIRE_INBOUND_DRAWDOWN_REQUEST") @JvmStatic fun of(value: String) = TransferType(JsonField.of(value)) } @@ -4784,7 +4784,7 @@ private constructor( WIRE_INBOUND_ADMIN, WIRE_OUTBOUND_PAYMENT, WIRE_OUTBOUND_ADMIN, - WIRE_DRAWDOWN_REQUEST, + WIRE_INBOUND_DRAWDOWN_REQUEST, } /** @@ -4805,7 +4805,7 @@ private constructor( WIRE_INBOUND_ADMIN, WIRE_OUTBOUND_PAYMENT, WIRE_OUTBOUND_ADMIN, - WIRE_DRAWDOWN_REQUEST, + WIRE_INBOUND_DRAWDOWN_REQUEST, /** * An enum member indicating that [TransferType] was instantiated with an unknown value. */ @@ -4829,7 +4829,7 @@ private constructor( WIRE_INBOUND_ADMIN -> Value.WIRE_INBOUND_ADMIN WIRE_OUTBOUND_PAYMENT -> Value.WIRE_OUTBOUND_PAYMENT WIRE_OUTBOUND_ADMIN -> Value.WIRE_OUTBOUND_ADMIN - WIRE_DRAWDOWN_REQUEST -> Value.WIRE_DRAWDOWN_REQUEST + WIRE_INBOUND_DRAWDOWN_REQUEST -> Value.WIRE_INBOUND_DRAWDOWN_REQUEST else -> Value._UNKNOWN } @@ -4852,7 +4852,7 @@ private constructor( WIRE_INBOUND_ADMIN -> Known.WIRE_INBOUND_ADMIN WIRE_OUTBOUND_PAYMENT -> Known.WIRE_OUTBOUND_PAYMENT WIRE_OUTBOUND_ADMIN -> Known.WIRE_OUTBOUND_ADMIN - WIRE_DRAWDOWN_REQUEST -> Known.WIRE_DRAWDOWN_REQUEST + WIRE_INBOUND_DRAWDOWN_REQUEST -> Known.WIRE_INBOUND_DRAWDOWN_REQUEST else -> throw LithicInvalidDataException("Unknown TransferType: $value") } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/VelocityLimitParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/VelocityLimitParams.kt index 4ec1ed19..5f98fc8d 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/VelocityLimitParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/VelocityLimitParams.kt @@ -23,9 +23,9 @@ import kotlin.jvm.optionals.getOrNull class VelocityLimitParams @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val filters: JsonField, private val period: JsonField, private val scope: JsonField, + private val filters: JsonField, private val limitAmount: JsonField, private val limitCount: JsonField, private val additionalProperties: MutableMap, @@ -33,24 +33,18 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("filters") - @ExcludeMissing - filters: JsonField = JsonMissing.of(), @JsonProperty("period") @ExcludeMissing period: JsonField = JsonMissing.of(), @JsonProperty("scope") @ExcludeMissing scope: JsonField = JsonMissing.of(), + @JsonProperty("filters") + @ExcludeMissing + filters: JsonField = JsonMissing.of(), @JsonProperty("limit_amount") @ExcludeMissing limitAmount: JsonField = JsonMissing.of(), @JsonProperty("limit_count") @ExcludeMissing limitCount: JsonField = JsonMissing.of(), - ) : this(filters, period, scope, limitAmount, limitCount, mutableMapOf()) - - /** - * @throws LithicInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun filters(): VelocityLimitFilters = filters.getRequired("filters") + ) : this(period, scope, filters, limitAmount, limitCount, mutableMapOf()) /** * Velocity over the current day since 00:00 / 12 AM in Eastern Time @@ -68,6 +62,12 @@ private constructor( */ fun scope(): VelocityScope = scope.getRequired("scope") + /** + * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun filters(): Optional = filters.getOptional("filters") + /** * The maximum amount of spend velocity allowed in the period in minor units (the smallest unit * of a currency, e.g. cents for USD). Transactions exceeding this limit will be declined. @@ -88,15 +88,6 @@ private constructor( */ fun limitCount(): Optional = limitCount.getOptional("limit_count") - /** - * Returns the raw JSON value of [filters]. - * - * Unlike [filters], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("filters") - @ExcludeMissing - fun _filters(): JsonField = filters - /** * Returns the raw JSON value of [period]. * @@ -111,6 +102,15 @@ private constructor( */ @JsonProperty("scope") @ExcludeMissing fun _scope(): JsonField = scope + /** + * Returns the raw JSON value of [filters]. + * + * Unlike [filters], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("filters") + @ExcludeMissing + fun _filters(): JsonField = filters + /** * Returns the raw JSON value of [limitAmount]. * @@ -144,7 +144,6 @@ private constructor( * * The following fields are required: * ```java - * .filters() * .period() * .scope() * ``` @@ -155,34 +154,23 @@ private constructor( /** A builder for [VelocityLimitParams]. */ class Builder internal constructor() { - private var filters: JsonField? = null private var period: JsonField? = null private var scope: JsonField? = null + private var filters: JsonField = JsonMissing.of() private var limitAmount: JsonField = JsonMissing.of() private var limitCount: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(velocityLimitParams: VelocityLimitParams) = apply { - filters = velocityLimitParams.filters period = velocityLimitParams.period scope = velocityLimitParams.scope + filters = velocityLimitParams.filters limitAmount = velocityLimitParams.limitAmount limitCount = velocityLimitParams.limitCount additionalProperties = velocityLimitParams.additionalProperties.toMutableMap() } - fun filters(filters: VelocityLimitFilters) = filters(JsonField.of(filters)) - - /** - * Sets [Builder.filters] to an arbitrary JSON value. - * - * You should usually call [Builder.filters] with a well-typed [VelocityLimitFilters] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun filters(filters: JsonField) = apply { this.filters = filters } - /** Velocity over the current day since 00:00 / 12 AM in Eastern Time */ fun period(period: VelocityLimitPeriod) = period(JsonField.of(period)) @@ -239,6 +227,17 @@ private constructor( */ fun scope(scope: JsonField) = apply { this.scope = scope } + fun filters(filters: VelocityLimitFilters) = filters(JsonField.of(filters)) + + /** + * Sets [Builder.filters] to an arbitrary JSON value. + * + * You should usually call [Builder.filters] with a well-typed [VelocityLimitFilters] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun filters(filters: JsonField) = apply { this.filters = filters } + /** * The maximum amount of spend velocity allowed in the period in minor units (the smallest * unit of a currency, e.g. cents for USD). Transactions exceeding this limit will be @@ -317,7 +316,6 @@ private constructor( * * The following fields are required: * ```java - * .filters() * .period() * .scope() * ``` @@ -326,9 +324,9 @@ private constructor( */ fun build(): VelocityLimitParams = VelocityLimitParams( - checkRequired("filters", filters), checkRequired("period", period), checkRequired("scope", scope), + filters, limitAmount, limitCount, additionalProperties.toMutableMap(), @@ -342,9 +340,9 @@ private constructor( return@apply } - filters().validate() period().validate() scope().validate() + filters().ifPresent { it.validate() } limitAmount() limitCount() validated = true @@ -365,12 +363,142 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (filters.asKnown().getOrNull()?.validity() ?: 0) + - (period.asKnown().getOrNull()?.validity() ?: 0) + + (period.asKnown().getOrNull()?.validity() ?: 0) + (scope.asKnown().getOrNull()?.validity() ?: 0) + + (filters.asKnown().getOrNull()?.validity() ?: 0) + (if (limitAmount.asKnown().isPresent) 1 else 0) + (if (limitCount.asKnown().isPresent) 1 else 0) + /** The scope the velocity is calculated for */ + class VelocityScope @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val CARD = of("CARD") + + @JvmField val ACCOUNT = of("ACCOUNT") + + @JvmStatic fun of(value: String) = VelocityScope(JsonField.of(value)) + } + + /** An enum containing [VelocityScope]'s known values. */ + enum class Known { + CARD, + ACCOUNT, + } + + /** + * An enum containing [VelocityScope]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [VelocityScope] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + CARD, + ACCOUNT, + /** + * An enum member indicating that [VelocityScope] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + CARD -> Value.CARD + ACCOUNT -> Value.ACCOUNT + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws LithicInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + CARD -> Known.CARD + ACCOUNT -> Known.ACCOUNT + else -> throw LithicInvalidDataException("Unknown VelocityScope: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws LithicInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { LithicInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): VelocityScope = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is VelocityScope && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + class VelocityLimitFilters @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( @@ -1037,156 +1165,26 @@ private constructor( "VelocityLimitFilters{excludeCountries=$excludeCountries, excludeMccs=$excludeMccs, includeCountries=$includeCountries, includeMccs=$includeMccs, includePanEntryModes=$includePanEntryModes, additionalProperties=$additionalProperties}" } - /** The scope the velocity is calculated for */ - class VelocityScope @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val CARD = of("CARD") - - @JvmField val ACCOUNT = of("ACCOUNT") - - @JvmStatic fun of(value: String) = VelocityScope(JsonField.of(value)) - } - - /** An enum containing [VelocityScope]'s known values. */ - enum class Known { - CARD, - ACCOUNT, - } - - /** - * An enum containing [VelocityScope]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [VelocityScope] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - CARD, - ACCOUNT, - /** - * An enum member indicating that [VelocityScope] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - CARD -> Value.CARD - ACCOUNT -> Value.ACCOUNT - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws LithicInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - CARD -> Known.CARD - ACCOUNT -> Known.ACCOUNT - else -> throw LithicInvalidDataException("Unknown VelocityScope: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws LithicInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { LithicInvalidDataException("Value is not a String") } - - private var validated: Boolean = false - - fun validate(): VelocityScope = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: LithicInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is VelocityScope && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is VelocityLimitParams && - filters == other.filters && period == other.period && scope == other.scope && + filters == other.filters && limitAmount == other.limitAmount && limitCount == other.limitCount && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(filters, period, scope, limitAmount, limitCount, additionalProperties) + Objects.hash(period, scope, filters, limitAmount, limitCount, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "VelocityLimitParams{filters=$filters, period=$period, scope=$scope, limitAmount=$limitAmount, limitCount=$limitCount, additionalProperties=$additionalProperties}" + "VelocityLimitParams{period=$period, scope=$scope, filters=$filters, limitAmount=$limitAmount, limitCount=$limitCount, additionalProperties=$additionalProperties}" } diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/VelocityLimitParamsTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/VelocityLimitParamsTest.kt index aa7693fb..7d219a89 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/VelocityLimitParamsTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/VelocityLimitParamsTest.kt @@ -13,6 +13,13 @@ internal class VelocityLimitParamsTest { fun create() { val velocityLimitParams = VelocityLimitParams.builder() + .period( + VelocityLimitPeriod.TrailingWindowObject.builder() + .duration(10L) + .type(VelocityLimitPeriod.TrailingWindowObject.Type.CUSTOM) + .build() + ) + .scope(VelocityLimitParams.VelocityScope.CARD) .filters( VelocityLimitParams.VelocityLimitFilters.builder() .addExcludeCountry("USD") @@ -24,19 +31,22 @@ internal class VelocityLimitParamsTest { ) .build() ) - .period( + .limitAmount(10000L) + .limitCount(0L) + .build() + + assertThat(velocityLimitParams.period()) + .isEqualTo( + VelocityLimitPeriod.ofTrailingWindowObject( VelocityLimitPeriod.TrailingWindowObject.builder() .duration(10L) .type(VelocityLimitPeriod.TrailingWindowObject.Type.CUSTOM) .build() ) - .scope(VelocityLimitParams.VelocityScope.CARD) - .limitAmount(10000L) - .limitCount(0L) - .build() - + ) + assertThat(velocityLimitParams.scope()).isEqualTo(VelocityLimitParams.VelocityScope.CARD) assertThat(velocityLimitParams.filters()) - .isEqualTo( + .contains( VelocityLimitParams.VelocityLimitFilters.builder() .addExcludeCountry("USD") .addExcludeMcc("5542") @@ -47,16 +57,6 @@ internal class VelocityLimitParamsTest { ) .build() ) - assertThat(velocityLimitParams.period()) - .isEqualTo( - VelocityLimitPeriod.ofTrailingWindowObject( - VelocityLimitPeriod.TrailingWindowObject.builder() - .duration(10L) - .type(VelocityLimitPeriod.TrailingWindowObject.Type.CUSTOM) - .build() - ) - ) - assertThat(velocityLimitParams.scope()).isEqualTo(VelocityLimitParams.VelocityScope.CARD) assertThat(velocityLimitParams.limitAmount()).contains(10000L) assertThat(velocityLimitParams.limitCount()).contains(0L) } @@ -66,6 +66,13 @@ internal class VelocityLimitParamsTest { val jsonMapper = jsonMapper() val velocityLimitParams = VelocityLimitParams.builder() + .period( + VelocityLimitPeriod.TrailingWindowObject.builder() + .duration(10L) + .type(VelocityLimitPeriod.TrailingWindowObject.Type.CUSTOM) + .build() + ) + .scope(VelocityLimitParams.VelocityScope.CARD) .filters( VelocityLimitParams.VelocityLimitFilters.builder() .addExcludeCountry("USD") @@ -77,13 +84,6 @@ internal class VelocityLimitParamsTest { ) .build() ) - .period( - VelocityLimitPeriod.TrailingWindowObject.builder() - .duration(10L) - .type(VelocityLimitPeriod.TrailingWindowObject.Type.CUSTOM) - .build() - ) - .scope(VelocityLimitParams.VelocityScope.CARD) .limitAmount(10000L) .limitCount(0L) .build() From e9f3ae9d5e5797a6458138d27e3b7a21fee0e9bd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:17:58 +0000 Subject: [PATCH 05/33] fix(api): Correct field name from ach_hold__period to ach_hold_period --- .stats.yml | 6 +++--- .../kotlin/com/lithic/api/models/PaymentCreateParams.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index ac611e10..ddf55aa9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-c06c4d54858775fef1de57e33d471e997cb28fe0c925fd7b08ba45fdd335e938.yml -openapi_spec_hash: 23745357b2171bcdfb5d30bfef1df48d -config_hash: 9dddee5f7af579864599849cb28a0770 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-64e9dd6979ae45f1bb6e77b40e8244ee46673332112ebf33fe2f3a287467ce85.yml +openapi_spec_hash: ce885445b66e95c5671ee72c01882d79 +config_hash: 07f0e0f3036a4a5825cee527bc46b0b6 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt index 5c7703b5..1769e780 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt @@ -1097,7 +1097,7 @@ private constructor( @JsonProperty("sec_code") @ExcludeMissing secCode: JsonField = JsonMissing.of(), - @JsonProperty("ach_hold__period") + @JsonProperty("ach_hold_period") @ExcludeMissing achHoldPeriod: JsonField = JsonMissing.of(), @JsonProperty("addenda") @ExcludeMissing addenda: JsonField = JsonMissing.of(), @@ -1115,7 +1115,7 @@ private constructor( * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun achHoldPeriod(): Optional = achHoldPeriod.getOptional("ach_hold__period") + fun achHoldPeriod(): Optional = achHoldPeriod.getOptional("ach_hold_period") /** * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -1136,7 +1136,7 @@ private constructor( * Unlike [achHoldPeriod], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("ach_hold__period") + @JsonProperty("ach_hold_period") @ExcludeMissing fun _achHoldPeriod(): JsonField = achHoldPeriod From bb604fbee3a368cfbe5c4e132f5974b691121255 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:03:09 +0000 Subject: [PATCH 06/33] chore: Rework event type generation to support spec splitting --- .stats.yml | 6 +++--- .../kotlin/com/lithic/api/models/PaymentCreateParams.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index ddf55aa9..ae10d57f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-64e9dd6979ae45f1bb6e77b40e8244ee46673332112ebf33fe2f3a287467ce85.yml -openapi_spec_hash: ce885445b66e95c5671ee72c01882d79 -config_hash: 07f0e0f3036a4a5825cee527bc46b0b6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-6e800837b020104545778d65b7b16bae277e6667d98044e83f3bfeacebdb489b.yml +openapi_spec_hash: 94788968e119e8665a1b0d4742565984 +config_hash: 2af43c32faa12490c9c9caa2ce62bccb diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt index 1769e780..5c7703b5 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt @@ -1097,7 +1097,7 @@ private constructor( @JsonProperty("sec_code") @ExcludeMissing secCode: JsonField = JsonMissing.of(), - @JsonProperty("ach_hold_period") + @JsonProperty("ach_hold__period") @ExcludeMissing achHoldPeriod: JsonField = JsonMissing.of(), @JsonProperty("addenda") @ExcludeMissing addenda: JsonField = JsonMissing.of(), @@ -1115,7 +1115,7 @@ private constructor( * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun achHoldPeriod(): Optional = achHoldPeriod.getOptional("ach_hold_period") + fun achHoldPeriod(): Optional = achHoldPeriod.getOptional("ach_hold__period") /** * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -1136,7 +1136,7 @@ private constructor( * Unlike [achHoldPeriod], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("ach_hold_period") + @JsonProperty("ach_hold__period") @ExcludeMissing fun _achHoldPeriod(): JsonField = achHoldPeriod From e4de24f1c5a533c8d8074fac447d64236d276dc4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:08:43 +0000 Subject: [PATCH 07/33] feat(api): Add idempotency key to cards POST and PATCH endpoints --- .stats.yml | 4 +- .../com/lithic/api/models/CardCreateParams.kt | 32 ++++++++-- .../lithic/api/models/CardCreateParamsTest.kt | 63 +++++++++++++++++++ .../FinancialAccountCreateParamsTest.kt | 8 +-- .../lithic/api/services/ErrorHandlingTest.kt | 17 +++++ .../lithic/api/services/ServiceParamsTest.kt | 1 + .../services/async/CardServiceAsyncTest.kt | 1 + .../async/FinancialAccountServiceAsyncTest.kt | 2 +- .../api/services/blocking/CardServiceTest.kt | 1 + .../blocking/FinancialAccountServiceTest.kt | 2 +- 10 files changed, 119 insertions(+), 12 deletions(-) diff --git a/.stats.yml b/.stats.yml index ae10d57f..bd16674f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-6e800837b020104545778d65b7b16bae277e6667d98044e83f3bfeacebdb489b.yml -openapi_spec_hash: 94788968e119e8665a1b0d4742565984 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-eeeb62a4869ba1436c9252f9630006a829695178e86305aea232f6be0d1e3d81.yml +openapi_spec_hash: 25bf9c499cd22240949862e622c534f2 config_hash: 2af43c32faa12490c9c9caa2ce62bccb diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt index dfb0bfaa..6503adf8 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt @@ -27,11 +27,14 @@ import kotlin.jvm.optionals.getOrNull */ class CardCreateParams private constructor( + private val idempotencyKey: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { + fun idempotencyKey(): Optional = Optional.ofNullable(idempotencyKey) + /** * Card types: * * `VIRTUAL` - Card will authorize at any merchant and can be added to a digital wallet like @@ -437,17 +440,25 @@ private constructor( /** A builder for [CardCreateParams]. */ class Builder internal constructor() { + private var idempotencyKey: String? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @JvmSynthetic internal fun from(cardCreateParams: CardCreateParams) = apply { + idempotencyKey = cardCreateParams.idempotencyKey body = cardCreateParams.body.toBuilder() additionalHeaders = cardCreateParams.additionalHeaders.toBuilder() additionalQueryParams = cardCreateParams.additionalQueryParams.toBuilder() } + fun idempotencyKey(idempotencyKey: String?) = apply { this.idempotencyKey = idempotencyKey } + + /** Alias for calling [Builder.idempotencyKey] with `idempotencyKey.orElse(null)`. */ + fun idempotencyKey(idempotencyKey: Optional) = + idempotencyKey(idempotencyKey.getOrNull()) + /** * Sets the entire request body. * @@ -974,12 +985,23 @@ private constructor( * @throws IllegalStateException if any required field is unset. */ fun build(): CardCreateParams = - CardCreateParams(body.build(), additionalHeaders.build(), additionalQueryParams.build()) + CardCreateParams( + idempotencyKey, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } fun _body(): Body = body - override fun _headers(): Headers = additionalHeaders + override fun _headers(): Headers = + Headers.builder() + .apply { + idempotencyKey?.let { put("Idempotency-Key", it) } + putAll(additionalHeaders) + } + .build() override fun _queryParams(): QueryParams = additionalQueryParams @@ -2835,13 +2857,15 @@ private constructor( } return other is CardCreateParams && + idempotencyKey == other.idempotencyKey && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams } - override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + override fun hashCode(): Int = + Objects.hash(idempotencyKey, body, additionalHeaders, additionalQueryParams) override fun toString() = - "CardCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "CardCreateParams{idempotencyKey=$idempotencyKey, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardCreateParamsTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardCreateParamsTest.kt index d570ffb8..a46f5a6d 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardCreateParamsTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardCreateParamsTest.kt @@ -2,6 +2,7 @@ package com.lithic.api.models +import com.lithic.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -10,6 +11,7 @@ internal class CardCreateParamsTest { @Test fun create() { CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -47,10 +49,71 @@ internal class CardCreateParamsTest { .build() } + @Test + fun headers() { + val params = + CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") + .type(CardCreateParams.Type.VIRTUAL) + .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") + .cardProgramToken("5e9483eb-8103-4e16-9794-2106111b2eca") + .carrier(Carrier.builder().qrCodeUrl("qr_code_url").build()) + .digitalCardArtToken("5e9483eb-8103-4e16-9794-2106111b2eca") + .expMonth("06") + .expYear("2027") + .memo("New Card") + .pin("pin") + .productId("1") + .replacementAccountToken("5e9483eb-8103-4e16-9794-2106111b2eca") + .replacementComment("replacement_comment") + .replacementFor("5e9483eb-8103-4e16-9794-2106111b2eca") + .replacementSubstatus(CardCreateParams.ReplacementSubstatus.LOST) + .shippingAddress( + ShippingAddress.builder() + .address1("5 Broad Street") + .city("NEW YORK") + .country("USA") + .firstName("Michael") + .lastName("Bluth") + .postalCode("10001-1809") + .state("NY") + .address2("Unit 25A") + .email("johnny@appleseed.com") + .line2Text("The Bluth Company") + .phoneNumber("+15555555555") + .build() + ) + .shippingMethod(CardCreateParams.ShippingMethod._2_DAY) + .spendLimit(1000L) + .spendLimitDuration(SpendLimitDuration.TRANSACTION) + .state(CardCreateParams.State.OPEN) + .build() + + val headers = params._headers() + + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("Idempotency-Key", "65a9dad4-1b60-4686-83fd-65b25078a4b4") + .build() + ) + } + + @Test + fun headersWithoutOptionalFields() { + val params = CardCreateParams.builder().type(CardCreateParams.Type.VIRTUAL).build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + @Test fun body() { val params = CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/FinancialAccountCreateParamsTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/FinancialAccountCreateParamsTest.kt index ddb3a154..e536da76 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/FinancialAccountCreateParamsTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/FinancialAccountCreateParamsTest.kt @@ -11,7 +11,7 @@ internal class FinancialAccountCreateParamsTest { @Test fun create() { FinancialAccountCreateParams.builder() - .idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .nickname("nickname") .type(FinancialAccountCreateParams.Type.OPERATING) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -23,7 +23,7 @@ internal class FinancialAccountCreateParamsTest { fun headers() { val params = FinancialAccountCreateParams.builder() - .idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .nickname("nickname") .type(FinancialAccountCreateParams.Type.OPERATING) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -35,7 +35,7 @@ internal class FinancialAccountCreateParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("Idempotency-Key", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("Idempotency-Key", "65a9dad4-1b60-4686-83fd-65b25078a4b4") .build() ) } @@ -57,7 +57,7 @@ internal class FinancialAccountCreateParamsTest { fun body() { val params = FinancialAccountCreateParams.builder() - .idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .nickname("nickname") .type(FinancialAccountCreateParams.Type.OPERATING) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/services/ErrorHandlingTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/services/ErrorHandlingTest.kt index 29d4f88b..d9911f25 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/services/ErrorHandlingTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/services/ErrorHandlingTest.kt @@ -75,6 +75,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -132,6 +133,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -189,6 +191,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -246,6 +249,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -303,6 +307,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -360,6 +365,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -417,6 +423,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -474,6 +481,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -531,6 +539,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -588,6 +597,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -645,6 +655,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -702,6 +713,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -759,6 +771,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -816,6 +829,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -873,6 +887,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -930,6 +945,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") @@ -985,6 +1001,7 @@ internal class ErrorHandlingTest { assertThrows { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/services/ServiceParamsTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/services/ServiceParamsTest.kt index 4e1916e3..43908cda 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/services/ServiceParamsTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/services/ServiceParamsTest.kt @@ -45,6 +45,7 @@ internal class ServiceParamsTest { cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/CardServiceAsyncTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/CardServiceAsyncTest.kt index 0c172028..04ab7e35 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/CardServiceAsyncTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/CardServiceAsyncTest.kt @@ -34,6 +34,7 @@ internal class CardServiceAsyncTest { val cardFuture = cardServiceAsync.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/FinancialAccountServiceAsyncTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/FinancialAccountServiceAsyncTest.kt index 3635d8fa..e7d77c8c 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/FinancialAccountServiceAsyncTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/services/async/FinancialAccountServiceAsyncTest.kt @@ -26,7 +26,7 @@ internal class FinancialAccountServiceAsyncTest { val financialAccountFuture = financialAccountServiceAsync.create( FinancialAccountCreateParams.builder() - .idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .nickname("nickname") .type(FinancialAccountCreateParams.Type.OPERATING) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/CardServiceTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/CardServiceTest.kt index 133e2da4..e24c6e1d 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/CardServiceTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/CardServiceTest.kt @@ -34,6 +34,7 @@ internal class CardServiceTest { val card = cardService.create( CardCreateParams.builder() + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .type(CardCreateParams.Type.VIRTUAL) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/FinancialAccountServiceTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/FinancialAccountServiceTest.kt index e67c7c0f..3ecb6bad 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/FinancialAccountServiceTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/FinancialAccountServiceTest.kt @@ -26,7 +26,7 @@ internal class FinancialAccountServiceTest { val financialAccount = financialAccountService.create( FinancialAccountCreateParams.builder() - .idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4") .nickname("nickname") .type(FinancialAccountCreateParams.Type.OPERATING) .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") From 7838ba8e1c5a14df27507a5aa6b7fb6444531a98 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 19:40:07 +0000 Subject: [PATCH 08/33] chore(internal): clean up maven repo artifact script and add html documentation to repo root --- scripts/upload-artifacts | 44 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index 729e6f22..df0c8d9f 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -7,6 +7,8 @@ GREEN='\033[32m' RED='\033[31m' NC='\033[0m' # No Color +MAVEN_REPO_PATH="./build/local-maven-repo" + log_error() { local msg="$1" local headers="$2" @@ -24,7 +26,7 @@ upload_file() { if [ -f "$file_name" ]; then echo -e "${GREEN}Processing file: $file_name${NC}" - pkg_file_name="mvn${file_name#./build/local-maven-repo}" + pkg_file_name="mvn${file_name#"${MAVEN_REPO_PATH}"}" # Get signed URL for uploading artifact file signed_url_response=$(curl -X POST -G "$URL" \ @@ -47,6 +49,7 @@ upload_file() { md5|sha1|sha256|sha512) content_type="text/plain" ;; module) content_type="application/json" ;; pom|xml) content_type="application/xml" ;; + html) content_type="text/html" ;; *) content_type="application/octet-stream" ;; esac @@ -81,6 +84,41 @@ walk_tree() { done } +generate_instructions() { + cat << EOF > "$MAVEN_REPO_PATH/index.html" + + + + Maven Repo + + +

Stainless SDK Maven Repository

+

This is the Maven repository for your Stainless Java SDK build.

+ +

Directions

+

To use the uploaded Maven repository, add the following to your project's pom.xml:

+
<repositories>
+    <repository>
+        <id>stainless-sdk-repo</id>
+        <url>https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn</url>
+    </repository>
+</repositories>
+ +

If you're using Gradle, add the following to your build.gradle file:

+
repositories {
+    maven {
+        url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'
+    }
+}
+ + +EOF + upload_file "${MAVEN_REPO_PATH}/index.html" + + echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" + echo "For more details, see the directions in https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn/index.html" +} + cd "$(dirname "$0")/.." echo "::group::Creating local Maven content" @@ -88,9 +126,9 @@ echo "::group::Creating local Maven content" echo "::endgroup::" echo "::group::Uploading to pkg.stainless.com" -walk_tree "./build/local-maven-repo" +walk_tree "$MAVEN_REPO_PATH" echo "::endgroup::" echo "::group::Generating instructions" -echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" +generate_instructions echo "::endgroup::" From ad467a4ae4e51a2dfd5e9b7be5800ae9d4ca56fc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 06:16:01 +0000 Subject: [PATCH 09/33] chore: test on Jackson 2.14.0 to avoid encountering FasterXML/jackson-databind#3240 in tests fix: date time deserialization leniency --- README.md | 2 ++ lithic-java-core/build.gradle.kts | 18 ++++++----- .../com/lithic/api/core/ObjectMappers.kt | 32 ++++++++++++------- .../api/models/CardProvisionResponse.kt | 2 +- .../com/lithic/api/models/ConditionalValue.kt | 2 +- .../com/lithic/api/core/ObjectMappersTest.kt | 15 ++------- .../lithic/api/models/ConditionalValueTest.kt | 17 +++++++--- lithic-java-proguard-test/build.gradle.kts | 2 +- 8 files changed, 51 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 234c6d0f..d23ab76b 100644 --- a/README.md +++ b/README.md @@ -416,6 +416,8 @@ If the SDK threw an exception, but you're _certain_ the version is compatible, t > [!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. +Also note that there are bugs in older Jackson versions that can affect the SDK. We don't work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead. + ## Network options ### Retries diff --git a/lithic-java-core/build.gradle.kts b/lithic-java-core/build.gradle.kts index 477ecb78..151c17eb 100644 --- a/lithic-java-core/build.gradle.kts +++ b/lithic-java-core/build.gradle.kts @@ -5,14 +5,16 @@ plugins { configurations.all { resolutionStrategy { - // Compile and test against a lower Jackson version to ensure we're compatible with it. - // We publish with a higher version (see below) to ensure users depend on a secure version by default. - force("com.fasterxml.jackson.core:jackson-core:2.13.4") - force("com.fasterxml.jackson.core:jackson-databind:2.13.4") - force("com.fasterxml.jackson.core:jackson-annotations:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4") - force("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + // Compile and test against a lower Jackson version to ensure we're compatible with it. Note that + // we generally support 2.13.4, but test against 2.14.0 because 2.13.4 has some annoying (but + // niche) bugs (users should upgrade if they encounter them). We publish with a higher version + // (see below) to ensure users depend on a secure version by default. + force("com.fasterxml.jackson.core:jackson-core:2.14.0") + force("com.fasterxml.jackson.core:jackson-databind:2.14.0") + force("com.fasterxml.jackson.core:jackson-annotations:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.0") + force("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt index 1154cadf..2414c30a 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt @@ -37,7 +37,7 @@ fun jsonMapper(): JsonMapper = .addModule( SimpleModule() .addSerializer(InputStreamSerializer) - .addDeserializer(LocalDateTime::class.java, LenientLocalDateTimeDeserializer()) + .addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer()) .addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer()) ) .withCoercionConfig(LogicalType.Boolean) { @@ -66,6 +66,12 @@ fun jsonMapper(): JsonMapper = .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) } + .withCoercionConfig(LogicalType.DateTime) { + it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } .withCoercionConfig(LogicalType.Array) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -126,10 +132,10 @@ private object InputStreamSerializer : BaseSerializer(InputStream:: } /** - * A deserializer that can deserialize [LocalDateTime] from datetimes, dates, and zoned datetimes. + * A deserializer that can deserialize [OffsetDateTime] from datetimes, dates, and zoned datetimes. */ -private class LenientLocalDateTimeDeserializer : - StdDeserializer(LocalDateTime::class.java) { +private class LenientOffsetDateTimeDeserializer : + StdDeserializer(OffsetDateTime::class.java) { companion object { @@ -143,7 +149,7 @@ private class LenientLocalDateTimeDeserializer : override fun logicalType(): LogicalType = LogicalType.DateTime - override fun deserialize(p: JsonParser, context: DeserializationContext?): LocalDateTime { + override fun deserialize(p: JsonParser, context: DeserializationContext): OffsetDateTime { val exceptions = mutableListOf() for (formatter in DATE_TIME_FORMATTERS) { @@ -151,18 +157,20 @@ private class LenientLocalDateTimeDeserializer : val temporal = formatter.parse(p.text) return when { - !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> - LocalDate.from(temporal).atStartOfDay() - !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> - LocalDateTime.from(temporal) - else -> ZonedDateTime.from(temporal).toLocalDateTime() - } + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal).atStartOfDay() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal) + else -> ZonedDateTime.from(temporal).toLocalDateTime() + } + .atZone(context.timeZone.toZoneId()) + .toOffsetDateTime() } catch (e: DateTimeException) { exceptions.add(e) } } - throw JsonParseException(p, "Cannot parse `LocalDateTime` from value: ${p.text}").apply { + throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply { exceptions.forEach { addSuppressed(it) } } } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardProvisionResponse.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardProvisionResponse.kt index bdbfb8a8..8382e238 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardProvisionResponse.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardProvisionResponse.kt @@ -364,7 +364,7 @@ private constructor( .toList() return when (bestMatches.size) { // This can happen if what we're deserializing is completely incompatible with - // all the possible variants (e.g. deserializing from array). + // all the possible variants (e.g. deserializing from boolean). 0 -> ProvisioningPayload(_json = json) 1 -> bestMatches.single() // If there's more than one match with the highest validity, then use the first diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt index 228c8504..9ba914ec 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt @@ -247,7 +247,7 @@ private constructor( .toList() return when (bestMatches.size) { // This can happen if what we're deserializing is completely incompatible with all - // the possible variants (e.g. deserializing from object). + // the possible variants (e.g. deserializing from boolean). 0 -> ConditionalValue(_json = json) 1 -> bestMatches.single() // If there's more than one match with the highest validity, then use the first diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt index 3977f517..6dd2c82b 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt @@ -3,7 +3,6 @@ package com.lithic.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.readValue -import java.time.LocalDateTime import java.time.OffsetDateTime import kotlin.reflect.KClass import org.assertj.core.api.Assertions.assertThat @@ -59,14 +58,6 @@ internal class ObjectMappersTest { LONG to DOUBLE, LONG to INTEGER, CLASS to MAP, - // These aren't actually valid, but coercion configs don't work for String until - // v2.14.0: https://github.com/FasterXML/jackson-databind/issues/3240 - // We currently test on v2.13.4. - BOOLEAN to STRING, - FLOAT to STRING, - DOUBLE to STRING, - INTEGER to STRING, - LONG to STRING, ) } } @@ -85,7 +76,7 @@ internal class ObjectMappersTest { } } - enum class LenientLocalDateTimeTestCase(val string: String) { + enum class LenientOffsetDateTimeTestCase(val string: String) { DATE("1998-04-21"), DATE_TIME("1998-04-21T04:00:00"), ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), @@ -94,11 +85,11 @@ internal class ObjectMappersTest { @ParameterizedTest @EnumSource - fun readLocalDateTime_lenient(testCase: LenientLocalDateTimeTestCase) { + fun readOffsetDateTime_lenient(testCase: LenientOffsetDateTimeTestCase) { val jsonMapper = jsonMapper() val json = jsonMapper.writeValueAsString(testCase.string) - assertDoesNotThrow { jsonMapper().readValue(json) } + assertDoesNotThrow { jsonMapper().readValue(json) } } enum class LenientOffsetDateTimeTestCase(val string: String) { diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ConditionalValueTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ConditionalValueTest.kt index 2c02b8bd..62d66056 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ConditionalValueTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ConditionalValueTest.kt @@ -10,6 +10,8 @@ import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource internal class ConditionalValueTest { @@ -118,10 +120,17 @@ internal class ConditionalValueTest { assertThat(roundtrippedConditionalValue).isEqualTo(conditionalValue) } - @Test - fun incompatibleJsonShapeDeserializesToUnknown() { - val value = JsonValue.from(mapOf("invalid" to "object")) - val conditionalValue = jsonMapper().convertValue(value, jacksonTypeRef()) + enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { + BOOLEAN(JsonValue.from(false)), + FLOAT(JsonValue.from(3.14)), + OBJECT(JsonValue.from(mapOf("invalid" to "object"))), + } + + @ParameterizedTest + @EnumSource + fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { + val conditionalValue = + jsonMapper().convertValue(testCase.value, jacksonTypeRef()) val e = assertThrows { conditionalValue.validate() } assertThat(e).hasMessageStartingWith("Unknown ") diff --git a/lithic-java-proguard-test/build.gradle.kts b/lithic-java-proguard-test/build.gradle.kts index d4d64f68..9f9c7fba 100644 --- a/lithic-java-proguard-test/build.gradle.kts +++ b/lithic-java-proguard-test/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.assertj:assertj-core:3.25.3") - testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } tasks.shadowJar { From 464fcaeefe3040303874976e8746601fb1d2cb0b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 12:57:39 +0000 Subject: [PATCH 10/33] fix(api): mark AppleWebPushProvisioningResponse fields required --- .stats.yml | 6 +-- .../api/models/CardWebProvisionResponse.kt | 39 ++++++++++++++----- .../lithic/api/models/PaymentCreateParams.kt | 6 +-- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/.stats.yml b/.stats.yml index bd16674f..021c6dec 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-eeeb62a4869ba1436c9252f9630006a829695178e86305aea232f6be0d1e3d81.yml -openapi_spec_hash: 25bf9c499cd22240949862e622c534f2 -config_hash: 2af43c32faa12490c9c9caa2ce62bccb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-d6e80e52c9f20d95780f2cf4869f80ee2c4b270ff9470941dc057e79d15bda1a.yml +openapi_spec_hash: f2bb7084cd5225769302589cd1563241 +config_hash: 31d71922d7838f34ae0875c9b8026d99 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardWebProvisionResponse.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardWebProvisionResponse.kt index 687d915a..28fece95 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardWebProvisionResponse.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardWebProvisionResponse.kt @@ -20,6 +20,7 @@ import com.lithic.api.core.JsonField import com.lithic.api.core.JsonMissing import com.lithic.api.core.JsonValue import com.lithic.api.core.allMaxBy +import com.lithic.api.core.checkRequired import com.lithic.api.core.getOrThrow import com.lithic.api.errors.LithicInvalidDataException import java.util.Collections @@ -256,18 +257,18 @@ private constructor( /** * JWS object required for handoff to Apple's script. * - * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun jws(): Optional = jws.getOptional("jws") + fun jws(): WebPushProvisioningResponseJws = jws.getRequired("jws") /** * A unique identifier for the JWS object. * - * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun state(): Optional = state.getOptional("state") + fun state(): String = state.getRequired("state") /** * Returns the raw JSON value of [jws]. @@ -302,6 +303,12 @@ private constructor( /** * Returns a mutable builder for constructing an instance of * [AppleWebPushProvisioningResponse]. + * + * The following fields are required: + * ```java + * .jws() + * .state() + * ``` */ @JvmStatic fun builder() = Builder() } @@ -309,8 +316,8 @@ private constructor( /** A builder for [AppleWebPushProvisioningResponse]. */ class Builder internal constructor() { - private var jws: JsonField = JsonMissing.of() - private var state: JsonField = JsonMissing.of() + private var jws: JsonField? = null + private var state: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -369,9 +376,21 @@ private constructor( * Returns an immutable instance of [AppleWebPushProvisioningResponse]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .jws() + * .state() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): AppleWebPushProvisioningResponse = - AppleWebPushProvisioningResponse(jws, state, additionalProperties.toMutableMap()) + AppleWebPushProvisioningResponse( + checkRequired("jws", jws), + checkRequired("state", state), + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -381,7 +400,7 @@ private constructor( return@apply } - jws().ifPresent { it.validate() } + jws().validate() state() validated = true } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt index 5c7703b5..1769e780 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/PaymentCreateParams.kt @@ -1097,7 +1097,7 @@ private constructor( @JsonProperty("sec_code") @ExcludeMissing secCode: JsonField = JsonMissing.of(), - @JsonProperty("ach_hold__period") + @JsonProperty("ach_hold_period") @ExcludeMissing achHoldPeriod: JsonField = JsonMissing.of(), @JsonProperty("addenda") @ExcludeMissing addenda: JsonField = JsonMissing.of(), @@ -1115,7 +1115,7 @@ private constructor( * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun achHoldPeriod(): Optional = achHoldPeriod.getOptional("ach_hold__period") + fun achHoldPeriod(): Optional = achHoldPeriod.getOptional("ach_hold_period") /** * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -1136,7 +1136,7 @@ private constructor( * Unlike [achHoldPeriod], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("ach_hold__period") + @JsonProperty("ach_hold_period") @ExcludeMissing fun _achHoldPeriod(): JsonField = achHoldPeriod From 737c025a59820d23176d4e45c50f9ab0781a791c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:08:43 +0000 Subject: [PATCH 11/33] chore(internal): improve maven repo docs --- scripts/upload-artifacts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index df0c8d9f..548d1527 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -56,12 +56,13 @@ upload_file() { # Upload file upload_response=$(curl -v -X PUT \ --retry 5 \ + --retry-all-errors \ -D "$tmp_headers" \ -H "Content-Type: $content_type" \ --data-binary "@${file_name}" "$signed_url" 2>&1) if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then - log_error "Failed upload artifact file" "$tmp_headers" "$upload_response" + log_error "Failed to upload artifact file" "$tmp_headers" "$upload_response" fi # Insert small throttle to reduce rate limiting risk @@ -110,6 +111,10 @@ generate_instructions() { url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn' } } + +

Once you've added the repository, you can include dependencies from it as usual. See your + project README + for more details.

EOF From ee7c05b2ab02d8cef3e3283ef2b4a1007d997e95 Mon Sep 17 00:00:00 2001 From: Tomer Aberbach Date: Fri, 16 Jan 2026 11:32:43 -0500 Subject: [PATCH 12/33] chore: fix build error --- .../com/lithic/api/core/ObjectMappers.kt | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt index 2414c30a..434ee65a 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt @@ -22,12 +22,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.kotlinModule import java.io.InputStream import java.time.DateTimeException -import java.time.LocalDate -import java.time.LocalDateTime import java.time.OffsetDateTime -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.temporal.ChronoField fun jsonMapper(): JsonMapper = JsonMapper.builder() @@ -38,7 +33,6 @@ fun jsonMapper(): JsonMapper = SimpleModule() .addSerializer(InputStreamSerializer) .addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer()) - .addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer()) ) .withCoercionConfig(LogicalType.Boolean) { it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -131,51 +125,6 @@ private object InputStreamSerializer : BaseSerializer(InputStream:: } } -/** - * A deserializer that can deserialize [OffsetDateTime] from datetimes, dates, and zoned datetimes. - */ -private class LenientOffsetDateTimeDeserializer : - StdDeserializer(OffsetDateTime::class.java) { - - companion object { - - private val DATE_TIME_FORMATTERS = - listOf( - DateTimeFormatter.ISO_LOCAL_DATE_TIME, - DateTimeFormatter.ISO_LOCAL_DATE, - DateTimeFormatter.ISO_ZONED_DATE_TIME, - ) - } - - override fun logicalType(): LogicalType = LogicalType.DateTime - - override fun deserialize(p: JsonParser, context: DeserializationContext): OffsetDateTime { - val exceptions = mutableListOf() - - for (formatter in DATE_TIME_FORMATTERS) { - try { - val temporal = formatter.parse(p.text) - - return when { - !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> - LocalDate.from(temporal).atStartOfDay() - !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> - LocalDateTime.from(temporal) - else -> ZonedDateTime.from(temporal).toLocalDateTime() - } - .atZone(context.timeZone.toZoneId()) - .toOffsetDateTime() - } catch (e: DateTimeException) { - exceptions.add(e) - } - } - - throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply { - exceptions.forEach { addSuppressed(it) } - } - } -} - /** * A deserializer that can deserialize [OffsetDateTime], assuming UTC when a timezone isn't given. */ From d9046f9a5eca4e5d4b8964c70a1c2144941d9b6a Mon Sep 17 00:00:00 2001 From: Tomer Aberbach Date: Fri, 16 Jan 2026 12:26:24 -0500 Subject: [PATCH 13/33] chore: fix build error --- .../com/lithic/api/core/ObjectMappersTest.kt | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt index 6dd2c82b..48cc29c6 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt @@ -91,19 +91,4 @@ internal class ObjectMappersTest { assertDoesNotThrow { jsonMapper().readValue(json) } } - - enum class LenientOffsetDateTimeTestCase(val string: String) { - DATE_TIME("1998-04-21T04:00:00"), - ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), - ZONED_DATE_TIME_2("1998-04-21T04:00:00Z"), - } - - @ParameterizedTest - @EnumSource - fun readOffsetDateTime_lenient(testCase: LenientOffsetDateTimeTestCase) { - val jsonMapper = jsonMapper() - val json = jsonMapper.writeValueAsString(testCase.string) - - assertDoesNotThrow { jsonMapper().readValue(json) } - } } From 29f6004a8cbba567f64ce4f0f681d4d5c7ef94f3 Mon Sep 17 00:00:00 2001 From: Tomer Aberbach Date: Fri, 16 Jan 2026 12:36:04 -0500 Subject: [PATCH 14/33] chore: fix test --- .../src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt index 48cc29c6..47d462ea 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt @@ -77,7 +77,6 @@ internal class ObjectMappersTest { } enum class LenientOffsetDateTimeTestCase(val string: String) { - DATE("1998-04-21"), DATE_TIME("1998-04-21T04:00:00"), ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), ZONED_DATE_TIME_2("1998-04-21T04:00:00Z"), From 126f8126438b97c2cc516aba5d85bf4abbe08352 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:24:37 +0000 Subject: [PATCH 15/33] fix(client): disallow coercion from float to int --- .../src/main/kotlin/com/lithic/api/core/ObjectMappers.kt | 1 + .../src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt index 434ee65a..bf3c1e2d 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt @@ -43,6 +43,7 @@ fun jsonMapper(): JsonMapper = } .withCoercionConfig(LogicalType.Integer) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) .setCoercion(CoercionInputShape.String, CoercionAction.Fail) .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt index 47d462ea..31927eea 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt @@ -46,11 +46,7 @@ internal class ObjectMappersTest { val VALID_CONVERSIONS = listOf( FLOAT to DOUBLE, - FLOAT to INTEGER, - FLOAT to LONG, DOUBLE to FLOAT, - DOUBLE to INTEGER, - DOUBLE to LONG, INTEGER to FLOAT, INTEGER to DOUBLE, INTEGER to LONG, From 6764fb4c842d48cffa5a6742f4c0a9ef132e0329 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:33:36 +0000 Subject: [PATCH 16/33] chore(internal): update `actions/checkout` version --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish-sonatype.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3fe4992..5d11fa22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 @@ -47,7 +47,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 @@ -85,7 +85,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/lithic-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index cd7b92ee..8db04218 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 445c0f6f..8cee1761 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'lithic-com/lithic-java' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Check release environment run: | From 0e39fefef9ef8651a56b5689e24e7965be4fbcbf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 09:19:05 +0000 Subject: [PATCH 17/33] fix: deserialization order --- .../com/lithic/api/models/ConditionalValue.kt | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt index 9ba914ec..dcaacaad 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/ConditionalValue.kt @@ -219,28 +219,18 @@ private constructor( val bestMatches = sequenceOf( - if (node.isNumber) { - tryDeserialize(node, jacksonTypeRef())?.let { - ConditionalValue(number = it, _json = json) - } - } else null, - if (node.isArray) { - tryDeserialize(node, jacksonTypeRef>())?.let { - ConditionalValue(listOfStrings = it, _json = json) - } - } else null, - // Try timestamp before generic string, since timestamps serialize as - // strings - if (node.isTextual) { - tryDeserialize(node, jacksonTypeRef())?.let { - ConditionalValue(timestamp = it, _json = json) - } - } else null, - if (node.isTextual) { - tryDeserialize(node, jacksonTypeRef())?.let { - ConditionalValue(regex = it, _json = json) - } - } else null, + tryDeserialize(node, jacksonTypeRef())?.let { + ConditionalValue(timestamp = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ConditionalValue(regex = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ConditionalValue(number = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>())?.let { + ConditionalValue(listOfStrings = it, _json = json) + }, ) .filterNotNull() .allMaxBy { it.validity() } From bd0a9da6fc8e2d9b4ed83a0c16b9e9afd5ceb42a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 20:18:17 +0000 Subject: [PATCH 18/33] fix(client): fully respect max retries fix(client): send retry count header for max retries 0 chore(internal): depend on packages directly in example --- .../lithic/api/client/okhttp/OkHttpClient.kt | 2 ++ .../api/core/http/RetryingHttpClient.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt index 1417591d..02e25515 100644 --- a/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt +++ b/lithic-java-client-okhttp/src/main/kotlin/com/lithic/api/client/okhttp/OkHttpClient.kt @@ -230,6 +230,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun build(): OkHttpClient = OkHttpClient( okhttp3.OkHttpClient.Builder() + // `RetryingHttpClient` handles retries if the user enabled them. + .retryOnConnectionFailure(false) .connectTimeout(timeout.connect()) .readTimeout(timeout.read()) .writeTimeout(timeout.write()) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/core/http/RetryingHttpClient.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/core/http/RetryingHttpClient.kt index e9c96400..5d2ac94f 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/core/http/RetryingHttpClient.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/core/http/RetryingHttpClient.kt @@ -31,10 +31,6 @@ private constructor( ) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.execute(request, requestOptions) - } - var modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -48,6 +44,10 @@ private constructor( modifiedRequest = setRetryCountHeader(modifiedRequest, retries) } + if (!isRetryable(modifiedRequest)) { + return httpClient.execute(modifiedRequest, requestOptions) + } + val response = try { val response = httpClient.execute(modifiedRequest, requestOptions) @@ -75,10 +75,6 @@ private constructor( request: HttpRequest, requestOptions: RequestOptions, ): CompletableFuture { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.executeAsync(request, requestOptions) - } - val modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -94,8 +90,12 @@ private constructor( val requestWithRetryCount = if (shouldSendRetryCount) setRetryCountHeader(request, retries) else request - return httpClient - .executeAsync(requestWithRetryCount, requestOptions) + val responseFuture = httpClient.executeAsync(requestWithRetryCount, requestOptions) + if (!isRetryable(requestWithRetryCount)) { + return responseFuture + } + + return responseFuture .handleAsync( fun( response: HttpResponse?, From 4e7e0b23375dcad5eda7626fd6f5dc83d774f4b7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 20:41:04 +0000 Subject: [PATCH 19/33] chore(ci): upgrade `actions/setup-java` --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish-sonatype.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d11fa22..bca5a903 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -50,7 +50,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -88,7 +88,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 8db04218..68a62dbb 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | From b437e45c988dfb6b2844b2d02ca397b2688d3521 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 10:34:38 +0000 Subject: [PATCH 20/33] chore: Add spec linter for YAML and folded style multiline strings --- .stats.yml | 4 ++-- .../com/lithic/api/models/FinancialTransaction.kt | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 021c6dec..4bf8e155 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-d6e80e52c9f20d95780f2cf4869f80ee2c4b270ff9470941dc057e79d15bda1a.yml -openapi_spec_hash: f2bb7084cd5225769302589cd1563241 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-a64e7cc23f0e28427e8a433dd951f05da5d35d982fe695ab2914941711bdfb0f.yml +openapi_spec_hash: 22ea6fa451b7bea3cc33a23d3aded4d6 config_hash: 31d71922d7838f34ae0875c9b8026d99 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/FinancialTransaction.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/FinancialTransaction.kt index d82a2df0..36cb0911 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/FinancialTransaction.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/FinancialTransaction.kt @@ -132,8 +132,9 @@ private constructor( /** * Pending amount of the transaction in the currency's smallest unit (e.g., cents), including - * any acquirer fees. The value of this field will go to zero over time once the financial - * transaction is settled. + * any acquirer fees. + * + * The value of this field will go to zero over time once the financial transaction is settled. * * @throws LithicInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -423,8 +424,10 @@ private constructor( /** * Pending amount of the transaction in the currency's smallest unit (e.g., cents), - * including any acquirer fees. The value of this field will go to zero over time once the - * financial transaction is settled. + * including any acquirer fees. + * + * The value of this field will go to zero over time once the financial transaction is + * settled. */ fun pendingAmount(pendingAmount: Long) = pendingAmount(JsonField.of(pendingAmount)) From 08c0ec5b07c9904a446496fbef297c3958b33adf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 22:28:47 +0000 Subject: [PATCH 21/33] feat(api): Add card.updated event --- .stats.yml | 4 +- .../api/models/CardUpdatedWebhookEvent.kt | 396 ++++++++++++++++++ .../kotlin/com/lithic/api/models/Event.kt | 9 + .../com/lithic/api/models/EventListParams.kt | 7 + .../lithic/api/models/EventSubscription.kt | 7 + .../models/EventSubscriptionCreateParams.kt | 7 + ...tSubscriptionSendSimulatedExampleParams.kt | 6 + .../models/EventSubscriptionUpdateParams.kt | 7 + .../lithic/api/models/ParsedWebhookEvent.kt | 28 ++ .../api/models/CardUpdatedWebhookEventTest.kt | 51 +++ .../api/models/ParsedWebhookEventTest.kt | 153 +++++++ 11 files changed, 673 insertions(+), 2 deletions(-) create mode 100644 lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt create mode 100644 lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt diff --git a/.stats.yml b/.stats.yml index 4bf8e155..048a5d63 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-a64e7cc23f0e28427e8a433dd951f05da5d35d982fe695ab2914941711bdfb0f.yml -openapi_spec_hash: 22ea6fa451b7bea3cc33a23d3aded4d6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-11ebfaf7523a8c0eafca9e2c914e44102537634be4b22289fe85d46b9ab3d650.yml +openapi_spec_hash: 38fdabb7812d528c839eadad87d49e5a config_hash: 31d71922d7838f34ae0875c9b8026d99 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt new file mode 100644 index 00000000..9ce3e82b --- /dev/null +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt @@ -0,0 +1,396 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.lithic.api.models + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.lithic.api.core.Enum +import com.lithic.api.core.ExcludeMissing +import com.lithic.api.core.JsonField +import com.lithic.api.core.JsonMissing +import com.lithic.api.core.JsonValue +import com.lithic.api.core.checkRequired +import com.lithic.api.errors.LithicInvalidDataException +import java.util.Collections +import java.util.Objects +import kotlin.jvm.optionals.getOrNull + +class CardUpdatedWebhookEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val token: JsonField, + private val eventType: JsonField, + private val previousFields: JsonValue, + private val state: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("token") @ExcludeMissing token: JsonField = JsonMissing.of(), + @JsonProperty("event_type") + @ExcludeMissing + eventType: JsonField = JsonMissing.of(), + @JsonProperty("previous_fields") + @ExcludeMissing + previousFields: JsonValue = JsonMissing.of(), + @JsonProperty("state") @ExcludeMissing state: JsonField = JsonMissing.of(), + ) : this(token, eventType, previousFields, state, mutableMapOf()) + + /** + * The token of the card that was updated. + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun token(): String = token.getRequired("token") + + /** + * The type of event that occurred. + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun eventType(): EventType = eventType.getRequired("event_type") + + /** The previous values of the fields that were updated. */ + @JsonProperty("previous_fields") + @ExcludeMissing + fun _previousFields(): JsonValue = previousFields + + /** + * The current state of the card. + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun state(): String = state.getRequired("state") + + /** + * Returns the raw JSON value of [token]. + * + * Unlike [token], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("token") @ExcludeMissing fun _token(): JsonField = token + + /** + * Returns the raw JSON value of [eventType]. + * + * Unlike [eventType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("event_type") @ExcludeMissing fun _eventType(): JsonField = eventType + + /** + * Returns the raw JSON value of [state]. + * + * Unlike [state], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("state") @ExcludeMissing fun _state(): JsonField = state + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [CardUpdatedWebhookEvent]. + * + * The following fields are required: + * ```java + * .token() + * .eventType() + * .previousFields() + * .state() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [CardUpdatedWebhookEvent]. */ + class Builder internal constructor() { + + private var token: JsonField? = null + private var eventType: JsonField? = null + private var previousFields: JsonValue? = null + private var state: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(cardUpdatedWebhookEvent: CardUpdatedWebhookEvent) = apply { + token = cardUpdatedWebhookEvent.token + eventType = cardUpdatedWebhookEvent.eventType + previousFields = cardUpdatedWebhookEvent.previousFields + state = cardUpdatedWebhookEvent.state + additionalProperties = cardUpdatedWebhookEvent.additionalProperties.toMutableMap() + } + + /** The token of the card that was updated. */ + fun token(token: String) = token(JsonField.of(token)) + + /** + * Sets [Builder.token] to an arbitrary JSON value. + * + * You should usually call [Builder.token] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun token(token: JsonField) = apply { this.token = token } + + /** The type of event that occurred. */ + fun eventType(eventType: EventType) = eventType(JsonField.of(eventType)) + + /** + * Sets [Builder.eventType] to an arbitrary JSON value. + * + * You should usually call [Builder.eventType] with a well-typed [EventType] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun eventType(eventType: JsonField) = apply { this.eventType = eventType } + + /** The previous values of the fields that were updated. */ + fun previousFields(previousFields: JsonValue) = apply { + this.previousFields = previousFields + } + + /** The current state of the card. */ + fun state(state: String) = state(JsonField.of(state)) + + /** + * Sets [Builder.state] to an arbitrary JSON value. + * + * You should usually call [Builder.state] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun state(state: JsonField) = apply { this.state = state } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [CardUpdatedWebhookEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .token() + * .eventType() + * .previousFields() + * .state() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): CardUpdatedWebhookEvent = + CardUpdatedWebhookEvent( + checkRequired("token", token), + checkRequired("eventType", eventType), + checkRequired("previousFields", previousFields), + checkRequired("state", state), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): CardUpdatedWebhookEvent = apply { + if (validated) { + return@apply + } + + token() + eventType().validate() + state() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (token.asKnown().isPresent) 1 else 0) + + (eventType.asKnown().getOrNull()?.validity() ?: 0) + + (if (state.asKnown().isPresent) 1 else 0) + + /** The type of event that occurred. */ + class EventType @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val CARD_UPDATED = of("card.updated") + + @JvmStatic fun of(value: String) = EventType(JsonField.of(value)) + } + + /** An enum containing [EventType]'s known values. */ + enum class Known { + CARD_UPDATED + } + + /** + * An enum containing [EventType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [EventType] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + CARD_UPDATED, + /** + * An enum member indicating that [EventType] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + CARD_UPDATED -> Value.CARD_UPDATED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws LithicInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + CARD_UPDATED -> Known.CARD_UPDATED + else -> throw LithicInvalidDataException("Unknown EventType: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws LithicInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { LithicInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): EventType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is EventType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CardUpdatedWebhookEvent && + token == other.token && + eventType == other.eventType && + previousFields == other.previousFields && + state == other.state && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(token, eventType, previousFields, state, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CardUpdatedWebhookEvent{token=$token, eventType=$eventType, previousFields=$previousFields, state=$state, additionalProperties=$additionalProperties}" +} diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Event.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Event.kt index 25fd19a2..59395bc2 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Event.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Event.kt @@ -82,6 +82,7 @@ private constructor( * - card.reissued: Occurs when a card is reissued. * - card.renewed: Occurs when a card is renewed. * - card.shipped: Occurs when a card is shipped. + * - card.updated: Occurs when a card is updated. * - digital_wallet.tokenization_approval_request: Occurs when a tokenization approval request * is made. This event will be deprecated in the future. We recommend using * `tokenization.approval_request` instead. @@ -280,6 +281,7 @@ private constructor( * - card.reissued: Occurs when a card is reissued. * - card.renewed: Occurs when a card is renewed. * - card.shipped: Occurs when a card is shipped. + * - card.updated: Occurs when a card is updated. * - digital_wallet.tokenization_approval_request: Occurs when a tokenization approval * request is made. This event will be deprecated in the future. We recommend using * `tokenization.approval_request` instead. @@ -467,6 +469,7 @@ private constructor( * - card.reissued: Occurs when a card is reissued. * - card.renewed: Occurs when a card is renewed. * - card.shipped: Occurs when a card is shipped. + * - card.updated: Occurs when a card is updated. * - digital_wallet.tokenization_approval_request: Occurs when a tokenization approval request * is made. This event will be deprecated in the future. We recommend using * `tokenization.approval_request` instead. @@ -584,6 +587,8 @@ private constructor( @JvmField val CARD_SHIPPED = of("card.shipped") + @JvmField val CARD_UPDATED = of("card.updated") + @JvmField val DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST = of("digital_wallet.tokenization_approval_request") @@ -690,6 +695,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -754,6 +760,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -823,6 +830,7 @@ private constructor( CARD_REISSUED -> Value.CARD_REISSUED CARD_RENEWED -> Value.CARD_RENEWED CARD_SHIPPED -> Value.CARD_SHIPPED + CARD_UPDATED -> Value.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Value.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Value.DIGITAL_WALLET_TOKENIZATION_RESULT @@ -896,6 +904,7 @@ private constructor( CARD_REISSUED -> Known.CARD_REISSUED CARD_RENEWED -> Known.CARD_RENEWED CARD_SHIPPED -> Known.CARD_SHIPPED + CARD_UPDATED -> Known.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Known.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Known.DIGITAL_WALLET_TOKENIZATION_RESULT diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventListParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventListParams.kt index befbe977..cd560478 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventListParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventListParams.kt @@ -340,6 +340,7 @@ private constructor( * - card.reissued: Occurs when a card is reissued. * - card.renewed: Occurs when a card is renewed. * - card.shipped: Occurs when a card is shipped. + * - card.updated: Occurs when a card is updated. * - digital_wallet.tokenization_approval_request: Occurs when a tokenization approval request * is made. This event will be deprecated in the future. We recommend using * `tokenization.approval_request` instead. @@ -457,6 +458,8 @@ private constructor( @JvmField val CARD_SHIPPED = of("card.shipped") + @JvmField val CARD_UPDATED = of("card.updated") + @JvmField val DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST = of("digital_wallet.tokenization_approval_request") @@ -563,6 +566,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -627,6 +631,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -696,6 +701,7 @@ private constructor( CARD_REISSUED -> Value.CARD_REISSUED CARD_RENEWED -> Value.CARD_RENEWED CARD_SHIPPED -> Value.CARD_SHIPPED + CARD_UPDATED -> Value.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Value.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Value.DIGITAL_WALLET_TOKENIZATION_RESULT @@ -769,6 +775,7 @@ private constructor( CARD_REISSUED -> Known.CARD_REISSUED CARD_RENEWED -> Known.CARD_RENEWED CARD_SHIPPED -> Known.CARD_SHIPPED + CARD_UPDATED -> Known.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Known.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Known.DIGITAL_WALLET_TOKENIZATION_RESULT diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscription.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscription.kt index 15bf5914..dac8945d 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscription.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscription.kt @@ -342,6 +342,7 @@ private constructor( * - card.reissued: Occurs when a card is reissued. * - card.renewed: Occurs when a card is renewed. * - card.shipped: Occurs when a card is shipped. + * - card.updated: Occurs when a card is updated. * - digital_wallet.tokenization_approval_request: Occurs when a tokenization approval request * is made. This event will be deprecated in the future. We recommend using * `tokenization.approval_request` instead. @@ -459,6 +460,8 @@ private constructor( @JvmField val CARD_SHIPPED = of("card.shipped") + @JvmField val CARD_UPDATED = of("card.updated") + @JvmField val DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST = of("digital_wallet.tokenization_approval_request") @@ -565,6 +568,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -629,6 +633,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -698,6 +703,7 @@ private constructor( CARD_REISSUED -> Value.CARD_REISSUED CARD_RENEWED -> Value.CARD_RENEWED CARD_SHIPPED -> Value.CARD_SHIPPED + CARD_UPDATED -> Value.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Value.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Value.DIGITAL_WALLET_TOKENIZATION_RESULT @@ -771,6 +777,7 @@ private constructor( CARD_REISSUED -> Known.CARD_REISSUED CARD_RENEWED -> Known.CARD_RENEWED CARD_SHIPPED -> Known.CARD_SHIPPED + CARD_UPDATED -> Known.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Known.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Known.DIGITAL_WALLET_TOKENIZATION_RESULT diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionCreateParams.kt index 9f7a4530..fb8b9362 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionCreateParams.kt @@ -664,6 +664,7 @@ private constructor( * - card.reissued: Occurs when a card is reissued. * - card.renewed: Occurs when a card is renewed. * - card.shipped: Occurs when a card is shipped. + * - card.updated: Occurs when a card is updated. * - digital_wallet.tokenization_approval_request: Occurs when a tokenization approval request * is made. This event will be deprecated in the future. We recommend using * `tokenization.approval_request` instead. @@ -781,6 +782,8 @@ private constructor( @JvmField val CARD_SHIPPED = of("card.shipped") + @JvmField val CARD_UPDATED = of("card.updated") + @JvmField val DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST = of("digital_wallet.tokenization_approval_request") @@ -887,6 +890,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -951,6 +955,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -1020,6 +1025,7 @@ private constructor( CARD_REISSUED -> Value.CARD_REISSUED CARD_RENEWED -> Value.CARD_RENEWED CARD_SHIPPED -> Value.CARD_SHIPPED + CARD_UPDATED -> Value.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Value.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Value.DIGITAL_WALLET_TOKENIZATION_RESULT @@ -1093,6 +1099,7 @@ private constructor( CARD_REISSUED -> Known.CARD_REISSUED CARD_RENEWED -> Known.CARD_RENEWED CARD_SHIPPED -> Known.CARD_SHIPPED + CARD_UPDATED -> Known.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Known.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Known.DIGITAL_WALLET_TOKENIZATION_RESULT diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionSendSimulatedExampleParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionSendSimulatedExampleParams.kt index 77147dd4..7781df70 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionSendSimulatedExampleParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionSendSimulatedExampleParams.kt @@ -463,6 +463,8 @@ private constructor( @JvmField val CARD_SHIPPED = of("card.shipped") + @JvmField val CARD_UPDATED = of("card.updated") + @JvmField val DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST = of("digital_wallet.tokenization_approval_request") @@ -569,6 +571,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -633,6 +636,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -702,6 +706,7 @@ private constructor( CARD_REISSUED -> Value.CARD_REISSUED CARD_RENEWED -> Value.CARD_RENEWED CARD_SHIPPED -> Value.CARD_SHIPPED + CARD_UPDATED -> Value.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Value.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Value.DIGITAL_WALLET_TOKENIZATION_RESULT @@ -775,6 +780,7 @@ private constructor( CARD_REISSUED -> Known.CARD_REISSUED CARD_RENEWED -> Known.CARD_RENEWED CARD_SHIPPED -> Known.CARD_SHIPPED + CARD_UPDATED -> Known.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Known.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Known.DIGITAL_WALLET_TOKENIZATION_RESULT diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionUpdateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionUpdateParams.kt index 0b45c8ae..d7b19ebf 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionUpdateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/EventSubscriptionUpdateParams.kt @@ -687,6 +687,7 @@ private constructor( * - card.reissued: Occurs when a card is reissued. * - card.renewed: Occurs when a card is renewed. * - card.shipped: Occurs when a card is shipped. + * - card.updated: Occurs when a card is updated. * - digital_wallet.tokenization_approval_request: Occurs when a tokenization approval request * is made. This event will be deprecated in the future. We recommend using * `tokenization.approval_request` instead. @@ -804,6 +805,8 @@ private constructor( @JvmField val CARD_SHIPPED = of("card.shipped") + @JvmField val CARD_UPDATED = of("card.updated") + @JvmField val DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST = of("digital_wallet.tokenization_approval_request") @@ -910,6 +913,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -974,6 +978,7 @@ private constructor( CARD_REISSUED, CARD_RENEWED, CARD_SHIPPED, + CARD_UPDATED, DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST, DIGITAL_WALLET_TOKENIZATION_RESULT, DIGITAL_WALLET_TOKENIZATION_TWO_FACTOR_AUTHENTICATION_CODE, @@ -1043,6 +1048,7 @@ private constructor( CARD_REISSUED -> Value.CARD_REISSUED CARD_RENEWED -> Value.CARD_RENEWED CARD_SHIPPED -> Value.CARD_SHIPPED + CARD_UPDATED -> Value.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Value.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Value.DIGITAL_WALLET_TOKENIZATION_RESULT @@ -1116,6 +1122,7 @@ private constructor( CARD_REISSUED -> Known.CARD_REISSUED CARD_RENEWED -> Known.CARD_RENEWED CARD_SHIPPED -> Known.CARD_SHIPPED + CARD_UPDATED -> Known.CARD_UPDATED DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST -> Known.DIGITAL_WALLET_TOKENIZATION_APPROVAL_REQUEST DIGITAL_WALLET_TOKENIZATION_RESULT -> Known.DIGITAL_WALLET_TOKENIZATION_RESULT diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/ParsedWebhookEvent.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/ParsedWebhookEvent.kt index ef5b9831..9444b8ad 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/ParsedWebhookEvent.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/ParsedWebhookEvent.kt @@ -55,6 +55,7 @@ private constructor( private val cardRenewed: CardRenewedWebhookEvent? = null, private val cardReissued: CardReissuedWebhookEvent? = null, private val cardShipped: CardShippedWebhookEvent? = null, + private val cardUpdated: CardUpdatedWebhookEvent? = null, private val cardTransactionUpdated: CardTransactionUpdatedWebhookEvent? = null, private val cardTransactionEnhancedDataCreated: CardTransactionEnhancedDataCreatedWebhookEvent? = @@ -164,6 +165,8 @@ private constructor( fun cardShipped(): Optional = Optional.ofNullable(cardShipped) + fun cardUpdated(): Optional = Optional.ofNullable(cardUpdated) + fun cardTransactionUpdated(): Optional = Optional.ofNullable(cardTransactionUpdated) @@ -334,6 +337,8 @@ private constructor( fun isCardShipped(): Boolean = cardShipped != null + fun isCardUpdated(): Boolean = cardUpdated != null + fun isCardTransactionUpdated(): Boolean = cardTransactionUpdated != null fun isCardTransactionEnhancedDataCreated(): Boolean = cardTransactionEnhancedDataCreated != null @@ -468,6 +473,8 @@ private constructor( fun asCardShipped(): CardShippedWebhookEvent = cardShipped.getOrThrow("cardShipped") + fun asCardUpdated(): CardUpdatedWebhookEvent = cardUpdated.getOrThrow("cardUpdated") + fun asCardTransactionUpdated(): CardTransactionUpdatedWebhookEvent = cardTransactionUpdated.getOrThrow("cardTransactionUpdated") @@ -639,6 +646,7 @@ private constructor( cardRenewed != null -> visitor.visitCardRenewed(cardRenewed) cardReissued != null -> visitor.visitCardReissued(cardReissued) cardShipped != null -> visitor.visitCardShipped(cardShipped) + cardUpdated != null -> visitor.visitCardUpdated(cardUpdated) cardTransactionUpdated != null -> visitor.visitCardTransactionUpdated(cardTransactionUpdated) cardTransactionEnhancedDataCreated != null -> @@ -818,6 +826,10 @@ private constructor( cardShipped.validate() } + override fun visitCardUpdated(cardUpdated: CardUpdatedWebhookEvent) { + cardUpdated.validate() + } + override fun visitCardTransactionUpdated( cardTransactionUpdated: CardTransactionUpdatedWebhookEvent ) { @@ -1138,6 +1150,9 @@ private constructor( override fun visitCardShipped(cardShipped: CardShippedWebhookEvent) = cardShipped.validity() + override fun visitCardUpdated(cardUpdated: CardUpdatedWebhookEvent) = + cardUpdated.validity() + override fun visitCardTransactionUpdated( cardTransactionUpdated: CardTransactionUpdatedWebhookEvent ) = cardTransactionUpdated.validity() @@ -1330,6 +1345,7 @@ private constructor( cardRenewed == other.cardRenewed && cardReissued == other.cardReissued && cardShipped == other.cardShipped && + cardUpdated == other.cardUpdated && cardTransactionUpdated == other.cardTransactionUpdated && cardTransactionEnhancedDataCreated == other.cardTransactionEnhancedDataCreated && cardTransactionEnhancedDataUpdated == other.cardTransactionEnhancedDataUpdated && @@ -1396,6 +1412,7 @@ private constructor( cardRenewed, cardReissued, cardShipped, + cardUpdated, cardTransactionUpdated, cardTransactionEnhancedDataCreated, cardTransactionEnhancedDataUpdated, @@ -1465,6 +1482,7 @@ private constructor( cardRenewed != null -> "ParsedWebhookEvent{cardRenewed=$cardRenewed}" cardReissued != null -> "ParsedWebhookEvent{cardReissued=$cardReissued}" cardShipped != null -> "ParsedWebhookEvent{cardShipped=$cardShipped}" + cardUpdated != null -> "ParsedWebhookEvent{cardUpdated=$cardUpdated}" cardTransactionUpdated != null -> "ParsedWebhookEvent{cardTransactionUpdated=$cardTransactionUpdated}" cardTransactionEnhancedDataCreated != null -> @@ -1626,6 +1644,10 @@ private constructor( fun ofCardShipped(cardShipped: CardShippedWebhookEvent) = ParsedWebhookEvent(cardShipped = cardShipped) + @JvmStatic + fun ofCardUpdated(cardUpdated: CardUpdatedWebhookEvent) = + ParsedWebhookEvent(cardUpdated = cardUpdated) + @JvmStatic fun ofCardTransactionUpdated(cardTransactionUpdated: CardTransactionUpdatedWebhookEvent) = ParsedWebhookEvent(cardTransactionUpdated = cardTransactionUpdated) @@ -1916,6 +1938,8 @@ private constructor( fun visitCardShipped(cardShipped: CardShippedWebhookEvent): T + fun visitCardUpdated(cardUpdated: CardUpdatedWebhookEvent): T + fun visitCardTransactionUpdated( cardTransactionUpdated: CardTransactionUpdatedWebhookEvent ): T @@ -2187,6 +2211,9 @@ private constructor( tryDeserialize(node, jacksonTypeRef())?.let { ParsedWebhookEvent(cardShipped = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef())?.let { + ParsedWebhookEvent(cardUpdated = it, _json = json) + }, tryDeserialize(node, jacksonTypeRef()) ?.let { ParsedWebhookEvent(cardTransactionUpdated = it, _json = json) }, tryDeserialize( @@ -2494,6 +2521,7 @@ private constructor( value.cardRenewed != null -> generator.writeObject(value.cardRenewed) value.cardReissued != null -> generator.writeObject(value.cardReissued) value.cardShipped != null -> generator.writeObject(value.cardShipped) + value.cardUpdated != null -> generator.writeObject(value.cardUpdated) value.cardTransactionUpdated != null -> generator.writeObject(value.cardTransactionUpdated) value.cardTransactionEnhancedDataCreated != null -> diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt new file mode 100644 index 00000000..be1f62ad --- /dev/null +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt @@ -0,0 +1,51 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.lithic.api.models + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.lithic.api.core.JsonValue +import com.lithic.api.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class CardUpdatedWebhookEventTest { + + @Test + fun create() { + val cardUpdatedWebhookEvent = + CardUpdatedWebhookEvent.builder() + .token("00000000-0000-0000-0000-000000000000") + .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) + .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) + .state("OPEN") + .build() + + assertThat(cardUpdatedWebhookEvent.token()) + .isEqualTo("00000000-0000-0000-0000-000000000000") + assertThat(cardUpdatedWebhookEvent.eventType()) + .isEqualTo(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) + assertThat(cardUpdatedWebhookEvent._previousFields()) + .isEqualTo(JsonValue.from(mapOf("state" to "PAUSED"))) + assertThat(cardUpdatedWebhookEvent.state()).isEqualTo("OPEN") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val cardUpdatedWebhookEvent = + CardUpdatedWebhookEvent.builder() + .token("00000000-0000-0000-0000-000000000000") + .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) + .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) + .state("OPEN") + .build() + + val roundtrippedCardUpdatedWebhookEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(cardUpdatedWebhookEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedCardUpdatedWebhookEvent).isEqualTo(cardUpdatedWebhookEvent) + } +} diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt index 88c47025..9c973e26 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt @@ -54,6 +54,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -241,6 +242,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -446,6 +448,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -571,6 +574,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -678,6 +682,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -804,6 +809,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -1112,6 +1118,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -1456,6 +1463,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -1654,6 +1662,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -1808,6 +1817,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -1961,6 +1971,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -2148,6 +2159,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -2287,6 +2299,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -2379,6 +2392,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -2474,6 +2488,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).contains(cardRenewed) assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -2569,6 +2584,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).contains(cardReissued) assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -2665,6 +2681,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).contains(cardShipped) + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -2734,6 +2751,102 @@ internal class ParsedWebhookEventTest { assertThat(roundtrippedParsedWebhookEvent).isEqualTo(parsedWebhookEvent) } + @Test + fun ofCardUpdated() { + val cardUpdated = + CardUpdatedWebhookEvent.builder() + .token("00000000-0000-0000-0000-000000000000") + .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) + .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) + .state("OPEN") + .build() + + val parsedWebhookEvent = ParsedWebhookEvent.ofCardUpdated(cardUpdated) + + assertThat(parsedWebhookEvent.accountHolderCreated()).isEmpty + assertThat(parsedWebhookEvent.kybPayload()).isEmpty + assertThat(parsedWebhookEvent.kycPayload()).isEmpty + assertThat(parsedWebhookEvent.legacyPayload()).isEmpty + assertThat(parsedWebhookEvent.accountHolderVerification()).isEmpty + assertThat(parsedWebhookEvent.accountHolderDocumentUpdated()).isEmpty + assertThat(parsedWebhookEvent.cardAuthorizationApprovalRequest()).isEmpty + assertThat(parsedWebhookEvent.tokenizationDecisioningRequest()).isEmpty + assertThat(parsedWebhookEvent.authRulesBacktestReportCreated()).isEmpty + assertThat(parsedWebhookEvent.balanceUpdated()).isEmpty + assertThat(parsedWebhookEvent.bookTransferTransactionCreated()).isEmpty + assertThat(parsedWebhookEvent.bookTransferTransactionUpdated()).isEmpty + assertThat(parsedWebhookEvent.cardCreated()).isEmpty + assertThat(parsedWebhookEvent.cardConverted()).isEmpty + assertThat(parsedWebhookEvent.cardRenewed()).isEmpty + assertThat(parsedWebhookEvent.cardReissued()).isEmpty + assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).contains(cardUpdated) + assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty + assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty + assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty + assertThat(parsedWebhookEvent.digitalWalletTokenizationApprovalRequest()).isEmpty + assertThat(parsedWebhookEvent.digitalWalletTokenizationResult()).isEmpty + assertThat(parsedWebhookEvent.digitalWalletTokenizationTwoFactorAuthenticationCode()) + .isEmpty + assertThat(parsedWebhookEvent.digitalWalletTokenizationTwoFactorAuthenticationCodeSent()) + .isEmpty + assertThat(parsedWebhookEvent.digitalWalletTokenizationUpdated()).isEmpty + assertThat(parsedWebhookEvent.disputeUpdated()).isEmpty + assertThat(parsedWebhookEvent.disputeEvidenceUploadFailed()).isEmpty + assertThat(parsedWebhookEvent.externalBankAccountCreated()).isEmpty + assertThat(parsedWebhookEvent.externalBankAccountUpdated()).isEmpty + assertThat(parsedWebhookEvent.externalPaymentCreated()).isEmpty + assertThat(parsedWebhookEvent.externalPaymentUpdated()).isEmpty + assertThat(parsedWebhookEvent.financialAccountCreated()).isEmpty + assertThat(parsedWebhookEvent.financialAccountUpdated()).isEmpty + assertThat(parsedWebhookEvent.fundingEventCreated()).isEmpty + assertThat(parsedWebhookEvent.loanTapeCreated()).isEmpty + assertThat(parsedWebhookEvent.loanTapeUpdated()).isEmpty + assertThat(parsedWebhookEvent.managementOperationCreated()).isEmpty + assertThat(parsedWebhookEvent.managementOperationUpdated()).isEmpty + assertThat(parsedWebhookEvent.internalTransactionCreated()).isEmpty + assertThat(parsedWebhookEvent.internalTransactionUpdated()).isEmpty + assertThat(parsedWebhookEvent.networkTotalCreated()).isEmpty + assertThat(parsedWebhookEvent.networkTotalUpdated()).isEmpty + assertThat(parsedWebhookEvent.paymentTransactionCreated()).isEmpty + assertThat(parsedWebhookEvent.paymentTransactionUpdated()).isEmpty + assertThat(parsedWebhookEvent.settlementReportUpdated()).isEmpty + assertThat(parsedWebhookEvent.statementsCreated()).isEmpty + assertThat(parsedWebhookEvent.threeDSAuthenticationCreated()).isEmpty + assertThat(parsedWebhookEvent.threeDSAuthenticationUpdated()).isEmpty + assertThat(parsedWebhookEvent.threeDSAuthenticationChallenge()).isEmpty + assertThat(parsedWebhookEvent.tokenizationApprovalRequest()).isEmpty + assertThat(parsedWebhookEvent.tokenizationResult()).isEmpty + assertThat(parsedWebhookEvent.tokenizationTwoFactorAuthenticationCode()).isEmpty + assertThat(parsedWebhookEvent.tokenizationTwoFactorAuthenticationCodeSent()).isEmpty + assertThat(parsedWebhookEvent.tokenizationUpdated()).isEmpty + assertThat(parsedWebhookEvent.threeDSAuthenticationApprovalRequest()).isEmpty + assertThat(parsedWebhookEvent.disputeTransactionCreated()).isEmpty + assertThat(parsedWebhookEvent.disputeTransactionUpdated()).isEmpty + } + + @Test + fun ofCardUpdatedRoundtrip() { + val jsonMapper = jsonMapper() + val parsedWebhookEvent = + ParsedWebhookEvent.ofCardUpdated( + CardUpdatedWebhookEvent.builder() + .token("00000000-0000-0000-0000-000000000000") + .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) + .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) + .state("OPEN") + .build() + ) + + val roundtrippedParsedWebhookEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(parsedWebhookEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedParsedWebhookEvent).isEqualTo(parsedWebhookEvent) + } + @Test fun ofCardTransactionUpdated() { val cardTransactionUpdated = @@ -2971,6 +3084,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).contains(cardTransactionUpdated) assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -3342,6 +3456,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()) .contains(cardTransactionEnhancedDataCreated) @@ -3546,6 +3661,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()) @@ -3774,6 +3890,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -3981,6 +4098,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -4132,6 +4250,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -4265,6 +4384,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -4423,6 +4543,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -4579,6 +4700,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -4696,6 +4818,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -4830,6 +4953,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -4988,6 +5112,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -5142,6 +5267,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -5293,6 +5419,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -5442,6 +5569,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -5588,6 +5716,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -5719,6 +5848,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -5983,6 +6113,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -6414,6 +6545,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -6737,6 +6869,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -6938,6 +7071,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -7109,6 +7243,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -7250,6 +7385,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -7386,6 +7522,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -7513,6 +7650,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -7683,6 +7821,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -7896,6 +8035,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -8070,6 +8210,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -8295,6 +8436,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -8634,6 +8776,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -9007,6 +9150,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -9409,6 +9553,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -9742,6 +9887,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -9939,6 +10085,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -10080,6 +10227,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -10210,6 +10358,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -10363,6 +10512,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -10637,6 +10787,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -10929,6 +11080,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty @@ -11134,6 +11286,7 @@ internal class ParsedWebhookEventTest { assertThat(parsedWebhookEvent.cardRenewed()).isEmpty assertThat(parsedWebhookEvent.cardReissued()).isEmpty assertThat(parsedWebhookEvent.cardShipped()).isEmpty + assertThat(parsedWebhookEvent.cardUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionUpdated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataCreated()).isEmpty assertThat(parsedWebhookEvent.cardTransactionEnhancedDataUpdated()).isEmpty From 746ee7fd9f55ea61a20c2d14f2486036b7d6211a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:17:21 +0000 Subject: [PATCH 22/33] feat(api): Add tags field to card transactions --- .stats.yml | 4 +- .../api/models/AccountActivityListResponse.kt | 48 +++++- ...ountActivityRetrieveTransactionResponse.kt | 48 +++++- .../CardTransactionUpdatedWebhookEvent.kt | 46 +++++- .../com/lithic/api/models/Transaction.kt | 147 +++++++++++++++++- .../models/AccountActivityListResponseTest.kt | 10 ++ ...ActivityRetrieveTransactionResponseTest.kt | 10 ++ .../CardTransactionUpdatedWebhookEventTest.kt | 17 ++ .../api/models/ParsedWebhookEventTest.kt | 10 ++ .../models/TransactionListPageResponseTest.kt | 16 ++ .../com/lithic/api/models/TransactionTest.kt | 17 ++ 11 files changed, 367 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 048a5d63..a90a83e7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-11ebfaf7523a8c0eafca9e2c914e44102537634be4b22289fe85d46b9ab3d650.yml -openapi_spec_hash: 38fdabb7812d528c839eadad87d49e5a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-1307147a7305d37c3eb288d87350e35d946c27e6b40dc8c6a00967d806dbade5.yml +openapi_spec_hash: 21c48156c56569871d503df54e2e1442 config_hash: 31d71922d7838f34ae0875c9b8026d99 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityListResponse.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityListResponse.kt index 24b75868..93a1516f 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityListResponse.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityListResponse.kt @@ -1732,6 +1732,7 @@ private constructor( private val result: JsonField, private val settledAmount: JsonField, private val status: JsonField, + private val tags: JsonField, private val tokenInfo: JsonField, private val updated: JsonField, private val events: JsonField>, @@ -1802,6 +1803,9 @@ private constructor( @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("tags") + @ExcludeMissing + tags: JsonField = JsonMissing.of(), @JsonProperty("token_info") @ExcludeMissing tokenInfo: JsonField = JsonMissing.of(), @@ -1836,6 +1840,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -1868,6 +1873,7 @@ private constructor( .result(result) .settledAmount(settledAmount) .status(status) + .tags(tags) .tokenInfo(tokenInfo) .updated(updated) .events(events) @@ -2066,6 +2072,15 @@ private constructor( */ fun status(): Transaction.Status = status.getRequired("status") + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata + * with a resource for your own purposes. + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun tags(): Transaction.Tags = tags.getRequired("tags") + /** * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -2308,6 +2323,13 @@ private constructor( @ExcludeMissing fun _status(): JsonField = status + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField = tags + /** * Returns the raw JSON value of [tokenInfo]. * @@ -2382,6 +2404,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * .family() @@ -2416,6 +2439,7 @@ private constructor( private var result: JsonField? = null private var settledAmount: JsonField? = null private var status: JsonField? = null + private var tags: JsonField? = null private var tokenInfo: JsonField? = null private var updated: JsonField? = null private var events: JsonField>? = null @@ -2447,6 +2471,7 @@ private constructor( result = cardTransaction.result settledAmount = cardTransaction.settledAmount status = cardTransaction.status + tags = cardTransaction.tags tokenInfo = cardTransaction.tokenInfo updated = cardTransaction.updated events = cardTransaction.events.map { it.toMutableList() } @@ -2902,6 +2927,21 @@ private constructor( */ fun status(status: JsonField) = apply { this.status = status } + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata + * with a resource for your own purposes. + */ + fun tags(tags: Transaction.Tags) = tags(JsonField.of(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed [Transaction.Tags] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField) = apply { this.tags = tags } + fun tokenInfo(tokenInfo: TokenInfo?) = tokenInfo(JsonField.ofNullable(tokenInfo)) /** Alias for calling [Builder.tokenInfo] with `tokenInfo.orElse(null)`. */ @@ -3014,6 +3054,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * .family() @@ -3046,6 +3087,7 @@ private constructor( checkRequired("result", result), checkRequired("settledAmount", settledAmount), checkRequired("status", status), + checkRequired("tags", tags), checkRequired("tokenInfo", tokenInfo), checkRequired("updated", updated), (events ?: JsonMissing.of()).map { it.toImmutable() }, @@ -3084,6 +3126,7 @@ private constructor( result().validate() settledAmount() status().validate() + tags().validate() tokenInfo().ifPresent { it.validate() } updated() events().ifPresent { it.forEach { it.validate() } } @@ -3130,6 +3173,7 @@ private constructor( (result.asKnown().getOrNull()?.validity() ?: 0) + (if (settledAmount.asKnown().isPresent) 1 else 0) + (status.asKnown().getOrNull()?.validity() ?: 0) + + (tags.asKnown().getOrNull()?.validity() ?: 0) + (tokenInfo.asKnown().getOrNull()?.validity() ?: 0) + (if (updated.asKnown().isPresent) 1 else 0) + (events.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + @@ -3446,6 +3490,7 @@ private constructor( result == other.result && settledAmount == other.settledAmount && status == other.status && + tags == other.tags && tokenInfo == other.tokenInfo && updated == other.updated && events == other.events && @@ -3478,6 +3523,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -3489,6 +3535,6 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "CardTransaction{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tokenInfo=$tokenInfo, updated=$updated, events=$events, family=$family, additionalProperties=$additionalProperties}" + "CardTransaction{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tags=$tags, tokenInfo=$tokenInfo, updated=$updated, events=$events, family=$family, additionalProperties=$additionalProperties}" } } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponse.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponse.kt index fd6f2044..8691ebef 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponse.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponse.kt @@ -1754,6 +1754,7 @@ private constructor( private val result: JsonField, private val settledAmount: JsonField, private val status: JsonField, + private val tags: JsonField, private val tokenInfo: JsonField, private val updated: JsonField, private val events: JsonField>, @@ -1824,6 +1825,9 @@ private constructor( @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("tags") + @ExcludeMissing + tags: JsonField = JsonMissing.of(), @JsonProperty("token_info") @ExcludeMissing tokenInfo: JsonField = JsonMissing.of(), @@ -1858,6 +1862,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -1890,6 +1895,7 @@ private constructor( .result(result) .settledAmount(settledAmount) .status(status) + .tags(tags) .tokenInfo(tokenInfo) .updated(updated) .events(events) @@ -2088,6 +2094,15 @@ private constructor( */ fun status(): Transaction.Status = status.getRequired("status") + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata + * with a resource for your own purposes. + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun tags(): Transaction.Tags = tags.getRequired("tags") + /** * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -2330,6 +2345,13 @@ private constructor( @ExcludeMissing fun _status(): JsonField = status + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField = tags + /** * Returns the raw JSON value of [tokenInfo]. * @@ -2404,6 +2426,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * .family() @@ -2438,6 +2461,7 @@ private constructor( private var result: JsonField? = null private var settledAmount: JsonField? = null private var status: JsonField? = null + private var tags: JsonField? = null private var tokenInfo: JsonField? = null private var updated: JsonField? = null private var events: JsonField>? = null @@ -2469,6 +2493,7 @@ private constructor( result = cardTransaction.result settledAmount = cardTransaction.settledAmount status = cardTransaction.status + tags = cardTransaction.tags tokenInfo = cardTransaction.tokenInfo updated = cardTransaction.updated events = cardTransaction.events.map { it.toMutableList() } @@ -2924,6 +2949,21 @@ private constructor( */ fun status(status: JsonField) = apply { this.status = status } + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata + * with a resource for your own purposes. + */ + fun tags(tags: Transaction.Tags) = tags(JsonField.of(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed [Transaction.Tags] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField) = apply { this.tags = tags } + fun tokenInfo(tokenInfo: TokenInfo?) = tokenInfo(JsonField.ofNullable(tokenInfo)) /** Alias for calling [Builder.tokenInfo] with `tokenInfo.orElse(null)`. */ @@ -3036,6 +3076,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * .family() @@ -3068,6 +3109,7 @@ private constructor( checkRequired("result", result), checkRequired("settledAmount", settledAmount), checkRequired("status", status), + checkRequired("tags", tags), checkRequired("tokenInfo", tokenInfo), checkRequired("updated", updated), (events ?: JsonMissing.of()).map { it.toImmutable() }, @@ -3106,6 +3148,7 @@ private constructor( result().validate() settledAmount() status().validate() + tags().validate() tokenInfo().ifPresent { it.validate() } updated() events().ifPresent { it.forEach { it.validate() } } @@ -3152,6 +3195,7 @@ private constructor( (result.asKnown().getOrNull()?.validity() ?: 0) + (if (settledAmount.asKnown().isPresent) 1 else 0) + (status.asKnown().getOrNull()?.validity() ?: 0) + + (tags.asKnown().getOrNull()?.validity() ?: 0) + (tokenInfo.asKnown().getOrNull()?.validity() ?: 0) + (if (updated.asKnown().isPresent) 1 else 0) + (events.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + @@ -3468,6 +3512,7 @@ private constructor( result == other.result && settledAmount == other.settledAmount && status == other.status && + tags == other.tags && tokenInfo == other.tokenInfo && updated == other.updated && events == other.events && @@ -3500,6 +3545,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -3511,6 +3557,6 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "CardTransaction{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tokenInfo=$tokenInfo, updated=$updated, events=$events, family=$family, additionalProperties=$additionalProperties}" + "CardTransaction{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tags=$tags, tokenInfo=$tokenInfo, updated=$updated, events=$events, family=$family, additionalProperties=$additionalProperties}" } } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEvent.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEvent.kt index 56b57bd5..6b7fce49 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEvent.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEvent.kt @@ -47,6 +47,7 @@ private constructor( private val result: JsonField, private val settledAmount: JsonField, private val status: JsonField, + private val tags: JsonField, private val tokenInfo: JsonField, private val updated: JsonField, private val events: JsonField>, @@ -113,6 +114,7 @@ private constructor( @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField = JsonMissing.of(), @JsonProperty("token_info") @ExcludeMissing tokenInfo: JsonField = JsonMissing.of(), @@ -149,6 +151,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -181,6 +184,7 @@ private constructor( .result(result) .settledAmount(settledAmount) .status(status) + .tags(tags) .tokenInfo(tokenInfo) .updated(updated) .events(events) @@ -378,6 +382,15 @@ private constructor( */ fun status(): Transaction.Status = status.getRequired("status") + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata with a + * resource for your own purposes. + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun tags(): Transaction.Tags = tags.getRequired("tags") + /** * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -612,6 +625,13 @@ private constructor( */ @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField = tags + /** * Returns the raw JSON value of [tokenInfo]. * @@ -685,6 +705,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * .eventType() @@ -719,6 +740,7 @@ private constructor( private var result: JsonField? = null private var settledAmount: JsonField? = null private var status: JsonField? = null + private var tags: JsonField? = null private var tokenInfo: JsonField? = null private var updated: JsonField? = null private var events: JsonField>? = null @@ -753,6 +775,7 @@ private constructor( result = cardTransactionUpdatedWebhookEvent.result settledAmount = cardTransactionUpdatedWebhookEvent.settledAmount status = cardTransactionUpdatedWebhookEvent.status + tags = cardTransactionUpdatedWebhookEvent.tags tokenInfo = cardTransactionUpdatedWebhookEvent.tokenInfo updated = cardTransactionUpdatedWebhookEvent.updated events = cardTransactionUpdatedWebhookEvent.events.map { it.toMutableList() } @@ -1196,6 +1219,21 @@ private constructor( */ fun status(status: JsonField) = apply { this.status = status } + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata + * with a resource for your own purposes. + */ + fun tags(tags: Transaction.Tags) = tags(JsonField.of(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed [Transaction.Tags] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField) = apply { this.tags = tags } + fun tokenInfo(tokenInfo: TokenInfo?) = tokenInfo(JsonField.ofNullable(tokenInfo)) /** Alias for calling [Builder.tokenInfo] with `tokenInfo.orElse(null)`. */ @@ -1308,6 +1346,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * .eventType() @@ -1340,6 +1379,7 @@ private constructor( checkRequired("result", result), checkRequired("settledAmount", settledAmount), checkRequired("status", status), + checkRequired("tags", tags), checkRequired("tokenInfo", tokenInfo), checkRequired("updated", updated), (events ?: JsonMissing.of()).map { it.toImmutable() }, @@ -1378,6 +1418,7 @@ private constructor( result().validate() settledAmount() status().validate() + tags().validate() tokenInfo().ifPresent { it.validate() } updated() events().ifPresent { it.forEach { it.validate() } } @@ -1423,6 +1464,7 @@ private constructor( (result.asKnown().getOrNull()?.validity() ?: 0) + (if (settledAmount.asKnown().isPresent) 1 else 0) + (status.asKnown().getOrNull()?.validity() ?: 0) + + (tags.asKnown().getOrNull()?.validity() ?: 0) + (tokenInfo.asKnown().getOrNull()?.validity() ?: 0) + (if (updated.asKnown().isPresent) 1 else 0) + (events.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + @@ -1579,6 +1621,7 @@ private constructor( result == other.result && settledAmount == other.settledAmount && status == other.status && + tags == other.tags && tokenInfo == other.tokenInfo && updated == other.updated && events == other.events && @@ -1611,6 +1654,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -1622,5 +1666,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "CardTransactionUpdatedWebhookEvent{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tokenInfo=$tokenInfo, updated=$updated, events=$events, eventType=$eventType, additionalProperties=$additionalProperties}" + "CardTransactionUpdatedWebhookEvent{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tags=$tags, tokenInfo=$tokenInfo, updated=$updated, events=$events, eventType=$eventType, additionalProperties=$additionalProperties}" } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Transaction.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Transaction.kt index ca86c905..1ccc1b31 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Transaction.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Transaction.kt @@ -47,6 +47,7 @@ private constructor( private val result: JsonField, private val settledAmount: JsonField, private val status: JsonField, + private val tags: JsonField, private val tokenInfo: JsonField, private val updated: JsonField, private val events: JsonField>, @@ -106,6 +107,7 @@ private constructor( @ExcludeMissing settledAmount: JsonField = JsonMissing.of(), @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField = JsonMissing.of(), @JsonProperty("token_info") @ExcludeMissing tokenInfo: JsonField = JsonMissing.of(), @@ -139,6 +141,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -337,6 +340,15 @@ private constructor( */ fun status(): Status = status.getRequired("status") + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata with a + * resource for your own purposes. + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun tags(): Tags = tags.getRequired("tags") + /** * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -557,6 +569,13 @@ private constructor( */ @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField = tags + /** * Returns the raw JSON value of [tokenInfo]. * @@ -622,6 +641,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * ``` @@ -655,6 +675,7 @@ private constructor( private var result: JsonField? = null private var settledAmount: JsonField? = null private var status: JsonField? = null + private var tags: JsonField? = null private var tokenInfo: JsonField? = null private var updated: JsonField? = null private var events: JsonField>? = null @@ -685,6 +706,7 @@ private constructor( result = transaction.result settledAmount = transaction.settledAmount status = transaction.status + tags = transaction.tags tokenInfo = transaction.tokenInfo updated = transaction.updated events = transaction.events.map { it.toMutableList() } @@ -1120,6 +1142,20 @@ private constructor( */ fun status(status: JsonField) = apply { this.status = status } + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata + * with a resource for your own purposes. + */ + fun tags(tags: Tags) = tags(JsonField.of(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed [Tags] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun tags(tags: JsonField) = apply { this.tags = tags } + fun tokenInfo(tokenInfo: TokenInfo?) = tokenInfo(JsonField.ofNullable(tokenInfo)) /** Alias for calling [Builder.tokenInfo] with `tokenInfo.orElse(null)`. */ @@ -1220,6 +1256,7 @@ private constructor( * .result() * .settledAmount() * .status() + * .tags() * .tokenInfo() * .updated() * ``` @@ -1251,6 +1288,7 @@ private constructor( checkRequired("result", result), checkRequired("settledAmount", settledAmount), checkRequired("status", status), + checkRequired("tags", tags), checkRequired("tokenInfo", tokenInfo), checkRequired("updated", updated), (events ?: JsonMissing.of()).map { it.toImmutable() }, @@ -1288,6 +1326,7 @@ private constructor( result().validate() settledAmount() status().validate() + tags().validate() tokenInfo().ifPresent { it.validate() } updated() events().ifPresent { it.forEach { it.validate() } } @@ -1332,6 +1371,7 @@ private constructor( (result.asKnown().getOrNull()?.validity() ?: 0) + (if (settledAmount.asKnown().isPresent) 1 else 0) + (status.asKnown().getOrNull()?.validity() ?: 0) + + (tags.asKnown().getOrNull()?.validity() ?: 0) + (tokenInfo.asKnown().getOrNull()?.validity() ?: 0) + (if (updated.asKnown().isPresent) 1 else 0) + (events.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) @@ -5361,6 +5401,109 @@ private constructor( override fun toString() = value.toString() } + /** + * Key-value pairs for tagging resources. Tags allow you to associate arbitrary metadata with a + * resource for your own purposes. + */ + class Tags + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Tags]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Tags]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(tags: Tags) = apply { + additionalProperties = tags.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Tags]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Tags = Tags(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Tags = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Tags && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Tags{additionalProperties=$additionalProperties}" + } + class TransactionEvent @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( @@ -11572,6 +11715,7 @@ private constructor( result == other.result && settledAmount == other.settledAmount && status == other.status && + tags == other.tags && tokenInfo == other.tokenInfo && updated == other.updated && events == other.events && @@ -11603,6 +11747,7 @@ private constructor( result, settledAmount, status, + tags, tokenInfo, updated, events, @@ -11613,5 +11758,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Transaction{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tokenInfo=$tokenInfo, updated=$updated, events=$events, additionalProperties=$additionalProperties}" + "Transaction{token=$token, accountToken=$accountToken, acquirerFee=$acquirerFee, acquirerReferenceNumber=$acquirerReferenceNumber, amount=$amount, amounts=$amounts, authorizationAmount=$authorizationAmount, authorizationCode=$authorizationCode, avs=$avs, cardToken=$cardToken, cardholderAuthentication=$cardholderAuthentication, created=$created, financialAccountToken=$financialAccountToken, merchant=$merchant, merchantAmount=$merchantAmount, merchantAuthorizationAmount=$merchantAuthorizationAmount, merchantCurrency=$merchantCurrency, network=$network, networkRiskScore=$networkRiskScore, pos=$pos, result=$result, settledAmount=$settledAmount, status=$status, tags=$tags, tokenInfo=$tokenInfo, updated=$updated, events=$events, additionalProperties=$additionalProperties}" } diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityListResponseTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityListResponseTest.kt index 9e26b11e..13e75cc7 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityListResponseTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityListResponseTest.kt @@ -327,6 +327,11 @@ internal class AccountActivityListResponseTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) .updated(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .addEvent( @@ -561,6 +566,11 @@ internal class AccountActivityListResponseTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo( TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build() ) diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponseTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponseTest.kt index d632243d..367dcbcd 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponseTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/AccountActivityRetrieveTransactionResponseTest.kt @@ -354,6 +354,11 @@ internal class AccountActivityRetrieveTransactionResponseTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) .updated(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .addEvent( @@ -589,6 +594,11 @@ internal class AccountActivityRetrieveTransactionResponseTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo( TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build() ) diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEventTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEventTest.kt index abfc1db7..39da2228 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEventTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardTransactionUpdatedWebhookEventTest.kt @@ -3,6 +3,7 @@ package com.lithic.api.models import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.lithic.api.core.JsonValue import com.lithic.api.core.jsonMapper import java.time.OffsetDateTime import kotlin.jvm.optionals.getOrNull @@ -116,6 +117,11 @@ internal class CardTransactionUpdatedWebhookEventTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) .updated(OffsetDateTime.parse("2023-08-03T18:42:30Z")) .addEvent( @@ -338,6 +344,12 @@ internal class CardTransactionUpdatedWebhookEventTest { assertThat(cardTransactionUpdatedWebhookEvent.settledAmount()).isEqualTo(0L) assertThat(cardTransactionUpdatedWebhookEvent.status()) .isEqualTo(Transaction.Status.PENDING) + assertThat(cardTransactionUpdatedWebhookEvent.tags()) + .isEqualTo( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) assertThat(cardTransactionUpdatedWebhookEvent.tokenInfo()) .contains(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) assertThat(cardTransactionUpdatedWebhookEvent.updated()) @@ -559,6 +571,11 @@ internal class CardTransactionUpdatedWebhookEventTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) .updated(OffsetDateTime.parse("2023-08-03T18:42:30Z")) .addEvent( diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt index 9c973e26..7f8bca02 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt @@ -2952,6 +2952,11 @@ internal class ParsedWebhookEventTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) .updated(OffsetDateTime.parse("2023-08-03T18:42:30Z")) .addEvent( @@ -3240,6 +3245,11 @@ internal class ParsedWebhookEventTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo( TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build() ) diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionListPageResponseTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionListPageResponseTest.kt index 4f9b292a..ad0113df 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionListPageResponseTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionListPageResponseTest.kt @@ -3,6 +3,7 @@ package com.lithic.api.models import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.lithic.api.core.JsonValue import com.lithic.api.core.jsonMapper import java.time.OffsetDateTime import kotlin.jvm.optionals.getOrNull @@ -124,6 +125,11 @@ internal class TransactionListPageResponseTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo( TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build() ) @@ -359,6 +365,11 @@ internal class TransactionListPageResponseTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo( TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build() ) @@ -595,6 +606,11 @@ internal class TransactionListPageResponseTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo( TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build() ) diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionTest.kt index ff471573..215d9a20 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionTest.kt @@ -3,6 +3,7 @@ package com.lithic.api.models import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.lithic.api.core.JsonValue import com.lithic.api.core.jsonMapper import java.time.OffsetDateTime import kotlin.jvm.optionals.getOrNull @@ -116,6 +117,11 @@ internal class TransactionTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) .updated(OffsetDateTime.parse("2023-08-03T18:42:30Z")) .addEvent( @@ -330,6 +336,12 @@ internal class TransactionTest { assertThat(transaction.result()).isEqualTo(Transaction.DeclineResult.APPROVED) assertThat(transaction.settledAmount()).isEqualTo(0L) assertThat(transaction.status()).isEqualTo(Transaction.Status.PENDING) + assertThat(transaction.tags()) + .isEqualTo( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) assertThat(transaction.tokenInfo()) .contains(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) assertThat(transaction.updated()).isEqualTo(OffsetDateTime.parse("2023-08-03T18:42:30Z")) @@ -548,6 +560,11 @@ internal class TransactionTest { .result(Transaction.DeclineResult.APPROVED) .settledAmount(0L) .status(Transaction.Status.PENDING) + .tags( + Transaction.Tags.builder() + .putAdditionalProperty("risk-level", JsonValue.from("high")) + .build() + ) .tokenInfo(TokenInfo.builder().walletType(TokenInfo.WalletType.APPLE_PAY).build()) .updated(OffsetDateTime.parse("2023-08-03T18:42:30Z")) .addEvent( From 03ea5d87c00f809b380b2c486c8d68300913cd33 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 15:58:29 +0000 Subject: [PATCH 23/33] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a90a83e7..4dc4c9aa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-1307147a7305d37c3eb288d87350e35d946c27e6b40dc8c6a00967d806dbade5.yml -openapi_spec_hash: 21c48156c56569871d503df54e2e1442 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-aa74f7b53f47c2bda4be2ee890578b6c99d26705fddb855013ea3c38b8f384f9.yml +openapi_spec_hash: 2d195f177651cd8ddb55937e8eef8995 config_hash: 31d71922d7838f34ae0875c9b8026d99 From 00cccfb7f68e4216728dd54d98f1de1deaab35ed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:12:40 +0000 Subject: [PATCH 24/33] chore(internal): update maven repo doc to include authentication --- scripts/upload-artifacts | 64 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index 548d1527..10f3c705 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -96,8 +96,52 @@ generate_instructions() {

Stainless SDK Maven Repository

This is the Maven repository for your Stainless Java SDK build.

-

Directions

-

To use the uploaded Maven repository, add the following to your project's pom.xml:

+

Project configuration

+ +

The details depend on whether you're using Maven or Gradle as your build tool.

+ +

Maven

+ +

Add the following to your project's pom.xml:

+
<repositories>
+    <repository>
+        <id>stainless-sdk-repo</id>
+        <url>https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn</url>
+    </repository>
+</repositories>
+ +

Gradle

+

Add the following to your build.gradle file:

+
repositories {
+    maven {
+        url "https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn"
+    }
+}
+ +
+

Configuring authentication (if required)

+ +

Some accounts may require authentication to access the repository. If so, use the + following instructions, replacing YOUR_STAINLESS_API_TOKEN with your actual token.

+ +

Maven with authentication

+ +

First, ensure you have the following in your Maven settings.xml for repo authentication:

+
<servers>
+    <server>
+        <id>stainless-sdk-repo</id>
+        <configuration>
+            <httpHeaders>
+                <property>
+                    <name>Authorization</name>
+                    <value>Bearer YOUR_STAINLESS_API_TOKEN</value>
+                </property>
+            </httpHeaders>
+        </configuration>
+    </server>
+</servers>
+ +

Then, add the following to your project's pom.xml:

<repositories>
     <repository>
         <id>stainless-sdk-repo</id>
@@ -105,14 +149,24 @@ generate_instructions() {
     </repository>
 </repositories>
-

If you're using Gradle, add the following to your build.gradle file:

+

Gradle with authentication

+

Add the following to your build.gradle file:

repositories {
     maven {
-        url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'
+        url "https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn"
+        credentials(HttpHeaderCredentials) {
+            name = "Authorization"
+            value = "Bearer YOUR_STAINLESS_API_TOKEN"
+        }
+        authentication {
+            header(HttpHeaderAuthentication)
+        }
     }
 }
+
-

Once you've added the repository, you can include dependencies from it as usual. See your +

Using the repository

+

Once you've configured the repository, you can include dependencies from it as usual. See your project README for more details.

From aa06e8dc2309292773fbd45a3f655709f3bdf550 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 21:11:47 +0000 Subject: [PATCH 25/33] feat(client): send `X-Stainless-Kotlin-Version` header --- .../src/main/kotlin/com/lithic/api/core/ClientOptions.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ClientOptions.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ClientOptions.kt index 0db2163f..87d897b8 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ClientOptions.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ClientOptions.kt @@ -475,6 +475,7 @@ private constructor( headers.put("X-Stainless-Package-Version", getPackageVersion()) headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) + headers.put("X-Stainless-Kotlin-Version", KotlinVersion.CURRENT.toString()) apiKey.let { if (!it.isEmpty()) { headers.put("Authorization", it) From 437340526d2b30ef5f07989118dfef51360dfa0c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 21:26:18 +0000 Subject: [PATCH 26/33] chore(internal): codegen related update --- examples/.keep | 4 ---- lithic-java-example/build.gradle.kts | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 examples/.keep diff --git a/examples/.keep b/examples/.keep deleted file mode 100644 index d8c73e93..00000000 --- a/examples/.keep +++ /dev/null @@ -1,4 +0,0 @@ -File generated from our OpenAPI spec by Stainless. - -This directory can be used to store example files demonstrating usage of this SDK. -It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/lithic-java-example/build.gradle.kts b/lithic-java-example/build.gradle.kts index ac0add4e..f6bd5bde 100644 --- a/lithic-java-example/build.gradle.kts +++ b/lithic-java-example/build.gradle.kts @@ -8,7 +8,8 @@ repositories { } dependencies { - implementation(project(":lithic-java")) + implementation(project(":lithic-java-core")) + implementation(project(":lithic-java-client-okhttp")) } tasks.withType().configureEach { From 672ca90c5ec7a68a6e73f9e2217d0a1c7cc9ef77 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 15:41:49 +0000 Subject: [PATCH 27/33] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4dc4c9aa..acfbe38e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-aa74f7b53f47c2bda4be2ee890578b6c99d26705fddb855013ea3c38b8f384f9.yml -openapi_spec_hash: 2d195f177651cd8ddb55937e8eef8995 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-14b3b5bca66c1e0935b314e469476f91193413c29a47ad4a0affa19beb14c7d3.yml +openapi_spec_hash: afba11ad031397d6e3873485b5b42473 config_hash: 31d71922d7838f34ae0875c9b8026d99 From da7b625d33dd3b68d657fbe34fd41e0b6f0aa564 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:55:18 +0000 Subject: [PATCH 28/33] docs: add comment for arbitrary value fields --- .../com/lithic/api/models/CardBulkOrder.kt | 9 ++++++- .../api/models/CardBulkOrderCreateParams.kt | 18 +++++++++++-- .../api/models/CardUpdatedWebhookEvent.kt | 9 ++++++- .../com/lithic/api/models/StatementTotals.kt | 27 ++++++++++++++++--- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrder.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrder.kt index 46e3f2d7..7de48325 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrder.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrder.kt @@ -103,7 +103,14 @@ private constructor( */ fun customerProductId(): Optional = customerProductId.getOptional("customer_product_id") - /** Shipping address for all cards in this bulk order */ + /** + * Shipping address for all cards in this bulk order + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = cardBulkOrder.shippingAddress().convert(MyClass.class); + * ``` + */ @JsonProperty("shipping_address") @ExcludeMissing fun _shippingAddress(): JsonValue = shippingAddress diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrderCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrderCreateParams.kt index d285b23c..98a6abe3 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrderCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardBulkOrderCreateParams.kt @@ -43,7 +43,14 @@ private constructor( */ fun customerProductId(): String = body.customerProductId() - /** Shipping address for all cards in this bulk order */ + /** + * Shipping address for all cards in this bulk order + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = cardBulkOrderCreateParams.shippingAddress().convert(MyClass.class); + * ``` + */ fun _shippingAddress(): JsonValue = body._shippingAddress() /** @@ -340,7 +347,14 @@ private constructor( */ fun customerProductId(): String = customerProductId.getRequired("customer_product_id") - /** Shipping address for all cards in this bulk order */ + /** + * Shipping address for all cards in this bulk order + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = createBulkOrderRequest.shippingAddress().convert(MyClass.class); + * ``` + */ @JsonProperty("shipping_address") @ExcludeMissing fun _shippingAddress(): JsonValue = shippingAddress diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt index 9ce3e82b..952b87e2 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt @@ -55,7 +55,14 @@ private constructor( */ fun eventType(): EventType = eventType.getRequired("event_type") - /** The previous values of the fields that were updated. */ + /** + * The previous values of the fields that were updated. + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = cardUpdatedWebhookEvent.previousFields().convert(MyClass.class); + * ``` + */ @JsonProperty("previous_fields") @ExcludeMissing fun _previousFields(): JsonValue = previousFields diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/StatementTotals.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/StatementTotals.kt index cbabdf77..5316d13c 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/StatementTotals.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/StatementTotals.kt @@ -130,13 +130,34 @@ private constructor( */ fun purchases(): Long = purchases.getRequired("purchases") - /** Breakdown of credits */ + /** + * Breakdown of credits + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = statementTotals.creditDetails().convert(MyClass.class); + * ``` + */ @JsonProperty("credit_details") @ExcludeMissing fun _creditDetails(): JsonValue = creditDetails - /** Breakdown of debits */ + /** + * Breakdown of debits + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = statementTotals.debitDetails().convert(MyClass.class); + * ``` + */ @JsonProperty("debit_details") @ExcludeMissing fun _debitDetails(): JsonValue = debitDetails - /** Breakdown of payments */ + /** + * Breakdown of payments + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = statementTotals.paymentDetails().convert(MyClass.class); + * ``` + */ @JsonProperty("payment_details") @ExcludeMissing fun _paymentDetails(): JsonValue = paymentDetails From ad49965c5aad1d8d310cd5fc47a15557d2aa1aa6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:05:59 +0000 Subject: [PATCH 29/33] chore(internal): correct cache invalidation for `SKIP_MOCK_TESTS` --- buildSrc/src/main/kotlin/lithic.kotlin.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/buildSrc/src/main/kotlin/lithic.kotlin.gradle.kts b/buildSrc/src/main/kotlin/lithic.kotlin.gradle.kts index 911f27dd..e09a84b2 100644 --- a/buildSrc/src/main/kotlin/lithic.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/lithic.kotlin.gradle.kts @@ -33,6 +33,9 @@ kotlin { tasks.withType().configureEach { systemProperty("junit.jupiter.execution.parallel.enabled", true) systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") + + // `SKIP_MOCK_TESTS` affects which tests run so it must be added as input for proper cache invalidation. + inputs.property("skipMockTests", System.getenv("SKIP_MOCK_TESTS")).optional(true) } val ktfmt by configurations.creating From b82b025bc29fc0454d1db1f790185309548cb4f0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:37:17 +0000 Subject: [PATCH 30/33] fix(client): preserve time zone in lenient date-time parsing --- .../com/lithic/api/core/ObjectMappers.kt | 45 ++++++++++++++----- .../com/lithic/api/core/ObjectMappersTest.kt | 40 ++++++++++++++--- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt index bf3c1e2d..c4084724 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt @@ -22,7 +22,12 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.kotlinModule import java.io.InputStream import java.time.DateTimeException +import java.time.LocalDate +import java.time.LocalDateTime import java.time.OffsetDateTime +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoField fun jsonMapper(): JsonMapper = JsonMapper.builder() @@ -127,25 +132,43 @@ private object InputStreamSerializer : BaseSerializer(InputStream:: } /** - * A deserializer that can deserialize [OffsetDateTime], assuming UTC when a timezone isn't given. + * A deserializer that can deserialize [OffsetDateTime] from datetimes, dates, and zoned datetimes. */ private class LenientOffsetDateTimeDeserializer : StdDeserializer(OffsetDateTime::class.java) { + + companion object { + + private val DATE_TIME_FORMATTERS = + listOf( + DateTimeFormatter.ISO_LOCAL_DATE_TIME, + DateTimeFormatter.ISO_LOCAL_DATE, + DateTimeFormatter.ISO_ZONED_DATE_TIME, + ) + } + override fun logicalType(): LogicalType = LogicalType.DateTime - override fun deserialize(p: JsonParser, context: DeserializationContext?): OffsetDateTime { + override fun deserialize(p: JsonParser, context: DeserializationContext): OffsetDateTime { val exceptions = mutableListOf() - try { - return OffsetDateTime.parse(p.text) - } catch (e: DateTimeException) { - exceptions.add(e) - } + for (formatter in DATE_TIME_FORMATTERS) { + try { + val temporal = formatter.parse(p.text) - try { - return OffsetDateTime.parse(p.text + 'Z') - } catch (e: DateTimeException) { - exceptions.add(e) + return when { + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal) + .atStartOfDay() + .atZone(ZoneId.of("UTC")) + .toOffsetDateTime() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal).atZone(ZoneId.of("UTC")).toOffsetDateTime() + else -> OffsetDateTime.from(temporal) + } + } catch (e: DateTimeException) { + exceptions.add(e) + } } throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply { diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt index 31927eea..15484386 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt @@ -3,12 +3,14 @@ package com.lithic.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.readValue +import java.time.LocalDate +import java.time.LocalTime import java.time.OffsetDateTime +import java.time.ZoneOffset import kotlin.reflect.KClass import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource import org.junitpioneer.jupiter.cartesian.CartesianTest @@ -72,10 +74,34 @@ internal class ObjectMappersTest { } } - enum class LenientOffsetDateTimeTestCase(val string: String) { - DATE_TIME("1998-04-21T04:00:00"), - ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), - ZONED_DATE_TIME_2("1998-04-21T04:00:00Z"), + enum class LenientOffsetDateTimeTestCase( + val string: String, + val expectedOffsetDateTime: OffsetDateTime, + ) { + DATE( + "1998-04-21", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(0, 0), ZoneOffset.UTC), + ), + DATE_TIME( + "1998-04-21T04:00:00", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(4, 0), ZoneOffset.UTC), + ), + ZONED_DATE_TIME_1( + "1998-04-21T04:00:00+03:00", + expectedOffsetDateTime = + OffsetDateTime.of( + LocalDate.of(1998, 4, 21), + LocalTime.of(4, 0), + ZoneOffset.ofHours(3), + ), + ), + ZONED_DATE_TIME_2( + "1998-04-21T04:00:00Z", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(4, 0), ZoneOffset.UTC), + ), } @ParameterizedTest @@ -84,6 +110,8 @@ internal class ObjectMappersTest { val jsonMapper = jsonMapper() val json = jsonMapper.writeValueAsString(testCase.string) - assertDoesNotThrow { jsonMapper().readValue(json) } + val offsetDateTime = jsonMapper().readValue(json) + + assertThat(offsetDateTime).isEqualTo(testCase.expectedOffsetDateTime) } } From ccebfa38275538c52ef8c62041351abc1ec68c27 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 18:16:25 +0000 Subject: [PATCH 31/33] chore(ci): upgrade `actions/github-script` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bca5a903..620a05d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: - name: Get GitHub OIDC Token if: github.repository == 'stainless-sdks/lithic-java' id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); From 5bf802286350906c6b6c27de3987bcce86a0090c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:52:43 +0000 Subject: [PATCH 32/33] docs: Remove deprecated tag from MERCHANT_LOCKED card type --- .stats.yml | 4 +- .../main/kotlin/com/lithic/api/models/Card.kt | 12 ++--- .../com/lithic/api/models/CardCreateParams.kt | 20 ++++----- .../api/models/CardUpdatedWebhookEvent.kt | 45 ++++++++++--------- .../com/lithic/api/models/NonPciCard.kt | 20 ++++----- .../api/models/CardUpdatedWebhookEventTest.kt | 6 +-- .../api/models/ParsedWebhookEventTest.kt | 4 +- 7 files changed, 56 insertions(+), 55 deletions(-) diff --git a/.stats.yml b/.stats.yml index acfbe38e..30dea04f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 176 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-14b3b5bca66c1e0935b314e469476f91193413c29a47ad4a0affa19beb14c7d3.yml -openapi_spec_hash: afba11ad031397d6e3873485b5b42473 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-a6c56df3bc156ac1e6ee5d635c6cd964f0d60836fe17a97deec8af8429bd339c.yml +openapi_spec_hash: c563acd10d96ddabe6c9643b592bd509 config_hash: 31d71922d7838f34ae0875c9b8026d99 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Card.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Card.kt index 086c5724..605ca9af 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/Card.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/Card.kt @@ -279,10 +279,10 @@ private constructor( * wallet like Apple Pay or Google Pay (if the card program is digital wallet-enabled). * * `PHYSICAL` - Manufactured and sent to the cardholder. We offer white label branding, credit, * ATM, PIN debit, chip/EMV, NFC and magstripe functionality. * `SINGLE_USE` - Card is closed - * upon first successful authorization. * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to - * the first merchant that successfully authorizes the card. * `UNLOCKED` - *[Deprecated]* - * Similar behavior to VIRTUAL cards, please use VIRTUAL instead. * `DIGITAL_WALLET` - - * *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL instead. + * upon first successful authorization. * `MERCHANT_LOCKED` - Card is locked to the first + * merchant that successfully authorizes the card. * `UNLOCKED` - *[Deprecated]* Similar + * behavior to VIRTUAL cards, please use VIRTUAL instead. * `DIGITAL_WALLET` - *[Deprecated]* + * Similar behavior to VIRTUAL cards, please use VIRTUAL instead. * * @throws LithicInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -936,8 +936,8 @@ private constructor( * wallet-enabled). * `PHYSICAL` - Manufactured and sent to the cardholder. We offer white * label branding, credit, ATM, PIN debit, chip/EMV, NFC and magstripe functionality. * * `SINGLE_USE` - Card is closed upon first successful authorization. * `MERCHANT_LOCKED` - - * *[Deprecated]* Card is locked to the first merchant that successfully authorizes the - * card. * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL + * Card is locked to the first merchant that successfully authorizes the card. * + * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL * instead. * `DIGITAL_WALLET` - *[Deprecated]* Similar behavior to VIRTUAL cards, please * use VIRTUAL instead. */ diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt index 6503adf8..552485e7 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt @@ -43,8 +43,8 @@ private constructor( * credit, ATM, PIN debit, chip/EMV, NFC and magstripe functionality. Reach out at * [lithic.com/contact](https://lithic.com/contact) for more information. * * `SINGLE_USE` - Card is closed upon first successful authorization. - * * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to the first merchant that successfully - * authorizes the card. + * * `MERCHANT_LOCKED` - Card is locked to the first merchant that successfully authorizes the + * card. * * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL instead. * * `DIGITAL_WALLET` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL * instead. @@ -481,8 +481,8 @@ private constructor( * credit, ATM, PIN debit, chip/EMV, NFC and magstripe functionality. Reach out at * [lithic.com/contact](https://lithic.com/contact) for more information. * * `SINGLE_USE` - Card is closed upon first successful authorization. - * * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to the first merchant that - * successfully authorizes the card. + * * `MERCHANT_LOCKED` - Card is locked to the first merchant that successfully authorizes + * the card. * * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL * instead. * * `DIGITAL_WALLET` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL @@ -1113,8 +1113,8 @@ private constructor( * credit, ATM, PIN debit, chip/EMV, NFC and magstripe functionality. Reach out at * [lithic.com/contact](https://lithic.com/contact) for more information. * * `SINGLE_USE` - Card is closed upon first successful authorization. - * * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to the first merchant that - * successfully authorizes the card. + * * `MERCHANT_LOCKED` - Card is locked to the first merchant that successfully authorizes + * the card. * * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL * instead. * * `DIGITAL_WALLET` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL @@ -1608,8 +1608,8 @@ private constructor( * branding, credit, ATM, PIN debit, chip/EMV, NFC and magstripe functionality. Reach * out at [lithic.com/contact](https://lithic.com/contact) for more information. * * `SINGLE_USE` - Card is closed upon first successful authorization. - * * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to the first merchant that - * successfully authorizes the card. + * * `MERCHANT_LOCKED` - Card is locked to the first merchant that successfully + * authorizes the card. * * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL * instead. * * `DIGITAL_WALLET` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use @@ -2186,8 +2186,8 @@ private constructor( * credit, ATM, PIN debit, chip/EMV, NFC and magstripe functionality. Reach out at * [lithic.com/contact](https://lithic.com/contact) for more information. * * `SINGLE_USE` - Card is closed upon first successful authorization. - * * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to the first merchant that successfully - * authorizes the card. + * * `MERCHANT_LOCKED` - Card is locked to the first merchant that successfully authorizes the + * card. * * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL instead. * * `DIGITAL_WALLET` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL * instead. diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt index 952b87e2..ee5b3323 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardUpdatedWebhookEvent.kt @@ -20,7 +20,7 @@ import kotlin.jvm.optionals.getOrNull class CardUpdatedWebhookEvent @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val token: JsonField, + private val cardToken: JsonField, private val eventType: JsonField, private val previousFields: JsonValue, private val state: JsonField, @@ -29,7 +29,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("token") @ExcludeMissing token: JsonField = JsonMissing.of(), + @JsonProperty("card_token") @ExcludeMissing cardToken: JsonField = JsonMissing.of(), @JsonProperty("event_type") @ExcludeMissing eventType: JsonField = JsonMissing.of(), @@ -37,7 +37,7 @@ private constructor( @ExcludeMissing previousFields: JsonValue = JsonMissing.of(), @JsonProperty("state") @ExcludeMissing state: JsonField = JsonMissing.of(), - ) : this(token, eventType, previousFields, state, mutableMapOf()) + ) : this(cardToken, eventType, previousFields, state, mutableMapOf()) /** * The token of the card that was updated. @@ -45,7 +45,7 @@ private constructor( * @throws LithicInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun token(): String = token.getRequired("token") + fun cardToken(): String = cardToken.getRequired("card_token") /** * The type of event that occurred. @@ -76,11 +76,11 @@ private constructor( fun state(): String = state.getRequired("state") /** - * Returns the raw JSON value of [token]. + * Returns the raw JSON value of [cardToken]. * - * Unlike [token], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [cardToken], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("token") @ExcludeMissing fun _token(): JsonField = token + @JsonProperty("card_token") @ExcludeMissing fun _cardToken(): JsonField = cardToken /** * Returns the raw JSON value of [eventType]. @@ -115,7 +115,7 @@ private constructor( * * The following fields are required: * ```java - * .token() + * .cardToken() * .eventType() * .previousFields() * .state() @@ -127,7 +127,7 @@ private constructor( /** A builder for [CardUpdatedWebhookEvent]. */ class Builder internal constructor() { - private var token: JsonField? = null + private var cardToken: JsonField? = null private var eventType: JsonField? = null private var previousFields: JsonValue? = null private var state: JsonField? = null @@ -135,7 +135,7 @@ private constructor( @JvmSynthetic internal fun from(cardUpdatedWebhookEvent: CardUpdatedWebhookEvent) = apply { - token = cardUpdatedWebhookEvent.token + cardToken = cardUpdatedWebhookEvent.cardToken eventType = cardUpdatedWebhookEvent.eventType previousFields = cardUpdatedWebhookEvent.previousFields state = cardUpdatedWebhookEvent.state @@ -143,15 +143,16 @@ private constructor( } /** The token of the card that was updated. */ - fun token(token: String) = token(JsonField.of(token)) + fun cardToken(cardToken: String) = cardToken(JsonField.of(cardToken)) /** - * Sets [Builder.token] to an arbitrary JSON value. + * Sets [Builder.cardToken] to an arbitrary JSON value. * - * You should usually call [Builder.token] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * You should usually call [Builder.cardToken] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun token(token: JsonField) = apply { this.token = token } + fun cardToken(cardToken: JsonField) = apply { this.cardToken = cardToken } /** The type of event that occurred. */ fun eventType(eventType: EventType) = eventType(JsonField.of(eventType)) @@ -207,7 +208,7 @@ private constructor( * * The following fields are required: * ```java - * .token() + * .cardToken() * .eventType() * .previousFields() * .state() @@ -217,7 +218,7 @@ private constructor( */ fun build(): CardUpdatedWebhookEvent = CardUpdatedWebhookEvent( - checkRequired("token", token), + checkRequired("cardToken", cardToken), checkRequired("eventType", eventType), checkRequired("previousFields", previousFields), checkRequired("state", state), @@ -232,7 +233,7 @@ private constructor( return@apply } - token() + cardToken() eventType().validate() state() validated = true @@ -253,7 +254,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (token.asKnown().isPresent) 1 else 0) + + (if (cardToken.asKnown().isPresent) 1 else 0) + (eventType.asKnown().getOrNull()?.validity() ?: 0) + (if (state.asKnown().isPresent) 1 else 0) @@ -385,7 +386,7 @@ private constructor( } return other is CardUpdatedWebhookEvent && - token == other.token && + cardToken == other.cardToken && eventType == other.eventType && previousFields == other.previousFields && state == other.state && @@ -393,11 +394,11 @@ private constructor( } private val hashCode: Int by lazy { - Objects.hash(token, eventType, previousFields, state, additionalProperties) + Objects.hash(cardToken, eventType, previousFields, state, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "CardUpdatedWebhookEvent{token=$token, eventType=$eventType, previousFields=$previousFields, state=$state, additionalProperties=$additionalProperties}" + "CardUpdatedWebhookEvent{cardToken=$cardToken, eventType=$eventType, previousFields=$previousFields, state=$state, additionalProperties=$additionalProperties}" } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/NonPciCard.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/NonPciCard.kt index c9a3056f..b736b2c5 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/NonPciCard.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/NonPciCard.kt @@ -243,10 +243,10 @@ private constructor( * wallet like Apple Pay or Google Pay (if the card program is digital wallet-enabled). * * `PHYSICAL` - Manufactured and sent to the cardholder. We offer white label branding, credit, * ATM, PIN debit, chip/EMV, NFC and magstripe functionality. * `SINGLE_USE` - Card is closed - * upon first successful authorization. * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to - * the first merchant that successfully authorizes the card. * `UNLOCKED` - *[Deprecated]* - * Similar behavior to VIRTUAL cards, please use VIRTUAL instead. * `DIGITAL_WALLET` - - * *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL instead. + * upon first successful authorization. * `MERCHANT_LOCKED` - Card is locked to the first + * merchant that successfully authorizes the card. * `UNLOCKED` - *[Deprecated]* Similar + * behavior to VIRTUAL cards, please use VIRTUAL instead. * `DIGITAL_WALLET` - *[Deprecated]* + * Similar behavior to VIRTUAL cards, please use VIRTUAL instead. * * @throws LithicInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -854,8 +854,8 @@ private constructor( * wallet-enabled). * `PHYSICAL` - Manufactured and sent to the cardholder. We offer white * label branding, credit, ATM, PIN debit, chip/EMV, NFC and magstripe functionality. * * `SINGLE_USE` - Card is closed upon first successful authorization. * `MERCHANT_LOCKED` - - * *[Deprecated]* Card is locked to the first merchant that successfully authorizes the - * card. * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL + * Card is locked to the first merchant that successfully authorizes the card. * + * `UNLOCKED` - *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL * instead. * `DIGITAL_WALLET` - *[Deprecated]* Similar behavior to VIRTUAL cards, please * use VIRTUAL instead. */ @@ -2279,10 +2279,10 @@ private constructor( * wallet like Apple Pay or Google Pay (if the card program is digital wallet-enabled). * * `PHYSICAL` - Manufactured and sent to the cardholder. We offer white label branding, credit, * ATM, PIN debit, chip/EMV, NFC and magstripe functionality. * `SINGLE_USE` - Card is closed - * upon first successful authorization. * `MERCHANT_LOCKED` - *[Deprecated]* Card is locked to - * the first merchant that successfully authorizes the card. * `UNLOCKED` - *[Deprecated]* - * Similar behavior to VIRTUAL cards, please use VIRTUAL instead. * `DIGITAL_WALLET` - - * *[Deprecated]* Similar behavior to VIRTUAL cards, please use VIRTUAL instead. + * upon first successful authorization. * `MERCHANT_LOCKED` - Card is locked to the first + * merchant that successfully authorizes the card. * `UNLOCKED` - *[Deprecated]* Similar + * behavior to VIRTUAL cards, please use VIRTUAL instead. * `DIGITAL_WALLET` - *[Deprecated]* + * Similar behavior to VIRTUAL cards, please use VIRTUAL instead. */ class Type @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt index be1f62ad..399d1e82 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CardUpdatedWebhookEventTest.kt @@ -14,13 +14,13 @@ internal class CardUpdatedWebhookEventTest { fun create() { val cardUpdatedWebhookEvent = CardUpdatedWebhookEvent.builder() - .token("00000000-0000-0000-0000-000000000000") + .cardToken("00000000-0000-0000-0000-000000000000") .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) .state("OPEN") .build() - assertThat(cardUpdatedWebhookEvent.token()) + assertThat(cardUpdatedWebhookEvent.cardToken()) .isEqualTo("00000000-0000-0000-0000-000000000000") assertThat(cardUpdatedWebhookEvent.eventType()) .isEqualTo(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) @@ -34,7 +34,7 @@ internal class CardUpdatedWebhookEventTest { val jsonMapper = jsonMapper() val cardUpdatedWebhookEvent = CardUpdatedWebhookEvent.builder() - .token("00000000-0000-0000-0000-000000000000") + .cardToken("00000000-0000-0000-0000-000000000000") .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) .state("OPEN") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt index 7f8bca02..92718683 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/ParsedWebhookEventTest.kt @@ -2755,7 +2755,7 @@ internal class ParsedWebhookEventTest { fun ofCardUpdated() { val cardUpdated = CardUpdatedWebhookEvent.builder() - .token("00000000-0000-0000-0000-000000000000") + .cardToken("00000000-0000-0000-0000-000000000000") .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) .state("OPEN") @@ -2831,7 +2831,7 @@ internal class ParsedWebhookEventTest { val parsedWebhookEvent = ParsedWebhookEvent.ofCardUpdated( CardUpdatedWebhookEvent.builder() - .token("00000000-0000-0000-0000-000000000000") + .cardToken("00000000-0000-0000-0000-000000000000") .eventType(CardUpdatedWebhookEvent.EventType.CARD_UPDATED) .previousFields(JsonValue.from(mapOf("state" to "PAUSED"))) .state("OPEN") From e6638d9affcdfe7ee606d10cfb406a3958e7dea6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:53:17 +0000 Subject: [PATCH 33/33] release: 0.116.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 53 +++++++++++++++++++++++++++++++++++ README.md | 10 +++---- build.gradle.kts | 2 +- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d3dc9f51..988e843f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.115.0" + ".": "0.116.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c879280a..d4d67af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,58 @@ # Changelog +## 0.116.0 (2026-01-26) + +Full Changelog: [v0.115.0...v0.116.0](https://github.com/lithic-com/lithic-java/compare/v0.115.0...v0.116.0) + +### Features + +* **api:** Add card.updated event ([08c0ec5](https://github.com/lithic-com/lithic-java/commit/08c0ec5b07c9904a446496fbef297c3958b33adf)) +* **api:** Add idempotency key to cards POST and PATCH endpoints ([e4de24f](https://github.com/lithic-com/lithic-java/commit/e4de24f1c5a533c8d8074fac447d64236d276dc4)) +* **api:** Add tags field to card transactions ([746ee7f](https://github.com/lithic-com/lithic-java/commit/746ee7fd9f55ea61a20c2d14f2486036b7d6211a)) +* **api:** make filter optional for Spend Velocity Auth Rules ([6122ecc](https://github.com/lithic-com/lithic-java/commit/6122eccf30d48db7aaba2fd6f8e94bf76fc7ceb4)) +* **client:** send `X-Stainless-Kotlin-Version` header ([aa06e8d](https://github.com/lithic-com/lithic-java/commit/aa06e8dc2309292773fbd45a3f655709f3bdf550)) + + +### Bug Fixes + +* **api:** Correct field name from ach_hold__period to ach_hold_period ([e9f3ae9](https://github.com/lithic-com/lithic-java/commit/e9f3ae9d5e5797a6458138d27e3b7a21fee0e9bd)) +* **api:** mark AppleWebPushProvisioningResponse fields required ([464fcae](https://github.com/lithic-com/lithic-java/commit/464fcaeefe3040303874976e8746601fb1d2cb0b)) +* **api:** rename WIRE_DRAWDOWN_REQUEST to WIRE_INBOUND_DRAWDOWN_REQUEST ([6122ecc](https://github.com/lithic-com/lithic-java/commit/6122eccf30d48db7aaba2fd6f8e94bf76fc7ceb4)) +* **client:** disallow coercion from float to int ([126f812](https://github.com/lithic-com/lithic-java/commit/126f8126438b97c2cc516aba5d85bf4abbe08352)) +* **client:** fully respect max retries ([bd0a9da](https://github.com/lithic-com/lithic-java/commit/bd0a9da6fc8e2d9b4ed83a0c16b9e9afd5ceb42a)) +* **client:** preserve time zone in lenient date-time parsing ([b82b025](https://github.com/lithic-com/lithic-java/commit/b82b025bc29fc0454d1db1f790185309548cb4f0)) +* **client:** send retry count header for max retries 0 ([bd0a9da](https://github.com/lithic-com/lithic-java/commit/bd0a9da6fc8e2d9b4ed83a0c16b9e9afd5ceb42a)) +* date time deserialization leniency ([ad467a4](https://github.com/lithic-com/lithic-java/commit/ad467a4ae4e51a2dfd5e9b7be5800ae9d4ca56fc)) +* deserialization order ([0e39fef](https://github.com/lithic-com/lithic-java/commit/0e39fefef9ef8651a56b5689e24e7965be4fbcbf)) + + +### Chores + +* Add spec linter for YAML and folded style multiline strings ([b437e45](https://github.com/lithic-com/lithic-java/commit/b437e45c988dfb6b2844b2d02ca397b2688d3521)) +* **ci:** upgrade `actions/github-script` ([ccebfa3](https://github.com/lithic-com/lithic-java/commit/ccebfa38275538c52ef8c62041351abc1ec68c27)) +* **ci:** upgrade `actions/setup-java` ([4e7e0b2](https://github.com/lithic-com/lithic-java/commit/4e7e0b23375dcad5eda7626fd6f5dc83d774f4b7)) +* configure new SDK language ([3dc7d3f](https://github.com/lithic-com/lithic-java/commit/3dc7d3f2903edec88f307dfa5d17e6b5f377e3f0)) +* fix build error ([d9046f9](https://github.com/lithic-com/lithic-java/commit/d9046f9a5eca4e5d4b8964c70a1c2144941d9b6a)) +* fix build error ([ee7c05b](https://github.com/lithic-com/lithic-java/commit/ee7c05b2ab02d8cef3e3283ef2b4a1007d997e95)) +* fix test ([29f6004](https://github.com/lithic-com/lithic-java/commit/29f6004a8cbba567f64ce4f0f681d4d5c7ef94f3)) +* **internal:** clean up maven repo artifact script and add html documentation to repo root ([7838ba8](https://github.com/lithic-com/lithic-java/commit/7838ba8e1c5a14df27507a5aa6b7fb6444531a98)) +* **internal:** codegen related update ([4373405](https://github.com/lithic-com/lithic-java/commit/437340526d2b30ef5f07989118dfef51360dfa0c)) +* **internal:** codegen related update ([6b3f7ee](https://github.com/lithic-com/lithic-java/commit/6b3f7ee38b9f387e28cce9d19d5fec3a6718cfbf)) +* **internal:** correct cache invalidation for `SKIP_MOCK_TESTS` ([ad49965](https://github.com/lithic-com/lithic-java/commit/ad49965c5aad1d8d310cd5fc47a15557d2aa1aa6)) +* **internal:** depend on packages directly in example ([bd0a9da](https://github.com/lithic-com/lithic-java/commit/bd0a9da6fc8e2d9b4ed83a0c16b9e9afd5ceb42a)) +* **internal:** improve maven repo docs ([737c025](https://github.com/lithic-com/lithic-java/commit/737c025a59820d23176d4e45c50f9ab0781a791c)) +* **internal:** support uploading Maven repo artifacts to stainless package server ([da51092](https://github.com/lithic-com/lithic-java/commit/da510920d18bdd6b4e2a655755e9fe21f145bf9f)) +* **internal:** update `actions/checkout` version ([6764fb4](https://github.com/lithic-com/lithic-java/commit/6764fb4c842d48cffa5a6742f4c0a9ef132e0329)) +* **internal:** update maven repo doc to include authentication ([00cccfb](https://github.com/lithic-com/lithic-java/commit/00cccfb7f68e4216728dd54d98f1de1deaab35ed)) +* Rework event type generation to support spec splitting ([bb604fb](https://github.com/lithic-com/lithic-java/commit/bb604fbee3a368cfbe5c4e132f5974b691121255)) +* test on Jackson 2.14.0 to avoid encountering FasterXML/jackson-databind[#3240](https://github.com/lithic-com/lithic-java/issues/3240) in tests ([ad467a4](https://github.com/lithic-com/lithic-java/commit/ad467a4ae4e51a2dfd5e9b7be5800ae9d4ca56fc)) + + +### Documentation + +* add comment for arbitrary value fields ([da7b625](https://github.com/lithic-com/lithic-java/commit/da7b625d33dd3b68d657fbe34fd41e0b6f0aa564)) +* Remove deprecated tag from MERCHANT_LOCKED card type ([5bf8022](https://github.com/lithic-com/lithic-java/commit/5bf802286350906c6b6c27de3987bcce86a0090c)) + ## 0.115.0 (2026-01-08) Full Changelog: [v0.114.0...v0.115.0](https://github.com/lithic-com/lithic-java/compare/v0.114.0...v0.115.0) diff --git a/README.md b/README.md index d23ab76b..7829b853 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.lithic.api/lithic-java)](https://central.sonatype.com/artifact/com.lithic.api/lithic-java/0.115.0) -[![javadoc](https://javadoc.io/badge2/com.lithic.api/lithic-java/0.115.0/javadoc.svg)](https://javadoc.io/doc/com.lithic.api/lithic-java/0.115.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.lithic.api/lithic-java)](https://central.sonatype.com/artifact/com.lithic.api/lithic-java/0.116.0) +[![javadoc](https://javadoc.io/badge2/com.lithic.api/lithic-java/0.116.0/javadoc.svg)](https://javadoc.io/doc/com.lithic.api/lithic-java/0.116.0) @@ -13,7 +13,7 @@ The Lithic Java SDK is similar to the Lithic Kotlin SDK but with minor differenc -The REST API documentation can be found on [docs.lithic.com](https://docs.lithic.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.lithic.api/lithic-java/0.115.0). +The REST API documentation can be found on [docs.lithic.com](https://docs.lithic.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.lithic.api/lithic-java/0.116.0). @@ -24,7 +24,7 @@ The REST API documentation can be found on [docs.lithic.com](https://docs.lithic ### Gradle ```kotlin -implementation("com.lithic.api:lithic-java:0.115.0") +implementation("com.lithic.api:lithic-java:0.116.0") ``` ### Maven @@ -33,7 +33,7 @@ implementation("com.lithic.api:lithic-java:0.115.0") com.lithic.api lithic-java - 0.115.0 + 0.116.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 1c30b48a..72a101ec 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.lithic.api" - version = "0.115.0" // x-release-please-version + version = "0.116.0" // x-release-please-version } subprojects {