diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7d7ae23..40ef7f83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 486a203f..4bab9967 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.120.0" + ".": "0.121.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 6976609b..b655e630 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 190 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-e88a4837037207e9591d48d534bd61acca57ca6e7c59ec0d4fdcf6e05288cc6d.yml -openapi_spec_hash: fd8bbc173d1b6dafd117fb1a3a3d446c -config_hash: 3005e2502301e77754e5e1455584525b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-5bb8d2bedef02f07498de3f252fa6da1393d2fb59f727b05828804cea9aded30.yml +openapi_spec_hash: d1f260252b3bb7ebc77fa7134db6c65d +config_hash: 400b9afe0f7f7b7d96177d05950775f9 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5443c14d..ff3fcdb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## 0.121.0 (2026-03-17) + +Full Changelog: [v0.120.0...v0.121.0](https://github.com/lithic-com/lithic-java/compare/v0.120.0...v0.121.0) + +### Features + +* **api:** add remittanceInformation field to Payment WireMethodAttributes ([5376d36](https://github.com/lithic-com/lithic-java/commit/5376d363c37079d13071d48914b445005aa5fedc)) + + +### Bug Fixes + +* add missing /v1/ prefix in getEmbedUrl URL path ([#645](https://github.com/lithic-com/lithic-java/issues/645)) ([fd56a40](https://github.com/lithic-com/lithic-java/commit/fd56a40d9ff25da51cf04e2f0600a7a0ae9ae284)) +* **client:** allow updating header/query affecting fields in `toBuilder()` ([17c55c1](https://github.com/lithic-com/lithic-java/commit/17c55c114f06e01c1027dc2867aeb5658b975cc1)) +* **types:** make address/dob/email/governmentId optional in KybDelegatedIndividual ([4b5460b](https://github.com/lithic-com/lithic-java/commit/4b5460bf47b1dab23891327c73370eaa05c71c1c)) + + +### Chores + +* **internal:** tweak CI branches ([0953db7](https://github.com/lithic-com/lithic-java/commit/0953db7ad2ef68b7de4d7158c4f64cafea9d94e5)) +* **internal:** update retry delay tests ([7232af2](https://github.com/lithic-com/lithic-java/commit/7232af2db25568bde898084260ce6f56c46f70c3)) + + +### Documentation + +* **api:** update supported file types in account holder upload document method ([50f96cd](https://github.com/lithic-com/lithic-java/commit/50f96cd53f37fa58a2b933c35568719e9f2b540f)) + ## 0.120.0 (2026-03-16) Full Changelog: [v0.119.0...v0.120.0](https://github.com/lithic-com/lithic-java/compare/v0.119.0...v0.120.0) diff --git a/README.md b/README.md index 145515af..9227368c 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.120.0) -[![javadoc](https://javadoc.io/badge2/com.lithic.api/lithic-java/0.120.0/javadoc.svg)](https://javadoc.io/doc/com.lithic.api/lithic-java/0.120.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.121.0) +[![javadoc](https://javadoc.io/badge2/com.lithic.api/lithic-java/0.121.0/javadoc.svg)](https://javadoc.io/doc/com.lithic.api/lithic-java/0.121.0) @@ -22,7 +22,7 @@ Use the Lithic MCP Server to enable AI assistants to interact with this API, all -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.120.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.121.0). @@ -33,7 +33,7 @@ The REST API documentation can be found on [docs.lithic.com](https://docs.lithic ### Gradle ```kotlin -implementation("com.lithic.api:lithic-java:0.120.0") +implementation("com.lithic.api:lithic-java:0.121.0") ``` ### Maven @@ -42,7 +42,7 @@ implementation("com.lithic.api:lithic-java:0.120.0") com.lithic.api lithic-java - 0.120.0 + 0.121.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index a704d259..c4924374 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.lithic.api" - version = "0.120.0" // x-release-please-version + version = "0.121.0" // x-release-please-version } subprojects { 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 87d897b8..f90712b8 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 @@ -476,13 +476,14 @@ private constructor( headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) headers.put("X-Stainless-Kotlin-Version", KotlinVersion.CURRENT.toString()) + // We replace after all the default headers to allow end-users to overwrite them. + headers.replaceAll(this.headers.build()) + queryParams.replaceAll(this.queryParams.build()) apiKey.let { if (!it.isEmpty()) { - headers.put("Authorization", it) + headers.replace("Authorization", it) } } - headers.replaceAll(this.headers.build()) - queryParams.replaceAll(this.queryParams.build()) return ClientOptions( httpClient, diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderCreateParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderCreateParams.kt index 6240d0c4..2d3d975b 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderCreateParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderCreateParams.kt @@ -450,8 +450,8 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val businessEntity: JsonField, - private val beneficialOwnerIndividuals: JsonField>, - private val controlPerson: JsonField, + private val beneficialOwnerIndividuals: JsonField>, + private val controlPerson: JsonField, private val externalId: JsonField, private val naicsCode: JsonField, private val natureOfBusiness: JsonField, @@ -468,10 +468,11 @@ private constructor( businessEntity: JsonField = JsonMissing.of(), @JsonProperty("beneficial_owner_individuals") @ExcludeMissing - beneficialOwnerIndividuals: JsonField> = JsonMissing.of(), + beneficialOwnerIndividuals: JsonField> = + JsonMissing.of(), @JsonProperty("control_person") @ExcludeMissing - controlPerson: JsonField = JsonMissing.of(), + controlPerson: JsonField = JsonMissing.of(), @JsonProperty("external_id") @ExcludeMissing externalId: JsonField = JsonMissing.of(), @@ -524,7 +525,7 @@ private constructor( * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun beneficialOwnerIndividuals(): Optional> = + fun beneficialOwnerIndividuals(): Optional> = beneficialOwnerIndividuals.getOptional("beneficial_owner_individuals") /** @@ -540,7 +541,7 @@ private constructor( * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun controlPerson(): Optional = + fun controlPerson(): Optional = controlPerson.getOptional("control_person") /** @@ -613,7 +614,7 @@ private constructor( */ @JsonProperty("beneficial_owner_individuals") @ExcludeMissing - fun _beneficialOwnerIndividuals(): JsonField> = + fun _beneficialOwnerIndividuals(): JsonField> = beneficialOwnerIndividuals /** @@ -624,7 +625,7 @@ private constructor( */ @JsonProperty("control_person") @ExcludeMissing - fun _controlPerson(): JsonField = controlPerson + fun _controlPerson(): JsonField = controlPerson /** * Returns the raw JSON value of [externalId]. @@ -715,9 +716,10 @@ private constructor( class Builder internal constructor() { private var businessEntity: JsonField? = null - private var beneficialOwnerIndividuals: JsonField>? = + private var beneficialOwnerIndividuals: + JsonField>? = null - private var controlPerson: JsonField = JsonMissing.of() + private var controlPerson: JsonField = JsonMissing.of() private var externalId: JsonField = JsonMissing.of() private var naicsCode: JsonField = JsonMissing.of() private var natureOfBusiness: JsonField = JsonMissing.of() @@ -764,29 +766,32 @@ private constructor( * [FinCEN requirements](https://www.fincen.gov/sites/default/files/shared/CDD_Rev6.7_Sept_2017_Certificate.pdf) * (Section I) for more background on individuals that should be included. */ - fun beneficialOwnerIndividuals(beneficialOwnerIndividuals: List) = - beneficialOwnerIndividuals(JsonField.of(beneficialOwnerIndividuals)) + fun beneficialOwnerIndividuals( + beneficialOwnerIndividuals: List + ) = beneficialOwnerIndividuals(JsonField.of(beneficialOwnerIndividuals)) /** * Sets [Builder.beneficialOwnerIndividuals] to an arbitrary JSON value. * * You should usually call [Builder.beneficialOwnerIndividuals] with a well-typed - * `List` value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. + * `List` value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. */ fun beneficialOwnerIndividuals( - beneficialOwnerIndividuals: JsonField> + beneficialOwnerIndividuals: JsonField> ) = apply { this.beneficialOwnerIndividuals = beneficialOwnerIndividuals.map { it.toMutableList() } } /** - * Adds a single [KybIndividual] to [beneficialOwnerIndividuals]. + * Adds a single [KybDelegatedIndividual] to [beneficialOwnerIndividuals]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addBeneficialOwnerIndividual(beneficialOwnerIndividual: KybIndividual) = apply { + fun addBeneficialOwnerIndividual( + beneficialOwnerIndividual: KybDelegatedIndividual + ) = apply { beneficialOwnerIndividuals = (beneficialOwnerIndividuals ?: JsonField.of(mutableListOf())).also { checkKnown("beneficialOwnerIndividuals", it) @@ -804,17 +809,17 @@ private constructor( * [FinCEN requirements](https://www.fincen.gov/sites/default/files/shared/CDD_Rev6.7_Sept_2017_Certificate.pdf) * (Section II) for more background. */ - fun controlPerson(controlPerson: KybIndividual) = + fun controlPerson(controlPerson: KybDelegatedIndividual) = controlPerson(JsonField.of(controlPerson)) /** * Sets [Builder.controlPerson] to an arbitrary JSON value. * - * You should usually call [Builder.controlPerson] with a well-typed [KybIndividual] - * value instead. This method is primarily for setting the field to an undocumented - * or not yet supported value. + * You should usually call [Builder.controlPerson] with a well-typed + * [KybDelegatedIndividual] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. */ - fun controlPerson(controlPerson: JsonField) = apply { + fun controlPerson(controlPerson: JsonField) = apply { this.controlPerson = controlPerson } @@ -1451,22 +1456,31 @@ private constructor( "KybDelegatedBusinessEntity{address=$address, legalBusinessName=$legalBusinessName, dbaBusinessName=$dbaBusinessName, governmentId=$governmentId, parentCompany=$parentCompany, phoneNumbers=$phoneNumbers, additionalProperties=$additionalProperties}" } - /** Individuals associated with a KYB application. Phone number is optional. */ - class KybIndividual + /** + * Individuals associated with a KYB_DELEGATED application. Only first and last name are + * required. + */ + class KybDelegatedIndividual @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val firstName: JsonField, + private val lastName: JsonField, private val address: JsonField
, private val dob: JsonField, private val email: JsonField, - private val firstName: JsonField, private val governmentId: JsonField, - private val lastName: JsonField, private val phoneNumber: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( + @JsonProperty("first_name") + @ExcludeMissing + firstName: JsonField = JsonMissing.of(), + @JsonProperty("last_name") + @ExcludeMissing + lastName: JsonField = JsonMissing.of(), @JsonProperty("address") @ExcludeMissing address: JsonField
= JsonMissing.of(), @@ -1474,87 +1488,77 @@ private constructor( @JsonProperty("email") @ExcludeMissing email: JsonField = JsonMissing.of(), - @JsonProperty("first_name") - @ExcludeMissing - firstName: JsonField = JsonMissing.of(), @JsonProperty("government_id") @ExcludeMissing governmentId: JsonField = JsonMissing.of(), - @JsonProperty("last_name") - @ExcludeMissing - lastName: JsonField = JsonMissing.of(), @JsonProperty("phone_number") @ExcludeMissing phoneNumber: JsonField = JsonMissing.of(), ) : this( + firstName, + lastName, address, dob, email, - firstName, governmentId, - lastName, phoneNumber, mutableMapOf(), ) /** - * Individual's current address - PO boxes, UPS drops, and FedEx drops are not - * acceptable; APO/FPO are acceptable. Only USA addresses are currently supported. + * Individual's first name, as it appears on government-issued identity documents. * * @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 address(): Address = address.getRequired("address") + fun firstName(): String = firstName.getRequired("first_name") /** - * Individual's date of birth, as an RFC 3339 date. + * Individual's last name, as it appears on government-issued identity documents. * * @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 dob(): String = dob.getRequired("dob") + fun lastName(): String = lastName.getRequired("last_name") /** - * Individual's email address. If utilizing Lithic for chargeback processing, this - * customer email address may be used to communicate dispute status and resolution. + * Individual's current address - PO boxes, UPS drops, and FedEx drops are not + * acceptable; APO/FPO are acceptable. Only USA addresses are currently supported. * - * @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). + * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). */ - fun email(): String = email.getRequired("email") + fun address(): Optional
= address.getOptional("address") /** - * Individual's first name, as it appears on government-issued identity documents. + * Individual's date of birth, as an RFC 3339 date. * - * @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). + * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). */ - fun firstName(): String = firstName.getRequired("first_name") + fun dob(): Optional = dob.getOptional("dob") /** - * Government-issued identification number (required for identity verification and - * compliance with banking regulations). Social Security Numbers (SSN) and - * Individual Taxpayer Identification Numbers (ITIN) are currently supported, - * entered as full nine-digits, with or without hyphens + * Individual's email address. If utilizing Lithic for chargeback processing, this + * customer email address may be used to communicate dispute status and resolution. * - * @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). + * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). */ - fun governmentId(): String = governmentId.getRequired("government_id") + fun email(): Optional = email.getOptional("email") /** - * Individual's last name, as it appears on government-issued identity documents. + * Government-issued identification number (required for identity verification and + * compliance with banking regulations). Social Security Numbers (SSN) and + * Individual Taxpayer Identification Numbers (ITIN) are currently supported, + * entered as full nine-digits, with or without hyphens * - * @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). + * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). */ - fun lastName(): String = lastName.getRequired("last_name") + fun governmentId(): Optional = governmentId.getOptional("government_id") /** * Individual's phone number, entered in E.164 format. @@ -1564,6 +1568,26 @@ private constructor( */ fun phoneNumber(): Optional = phoneNumber.getOptional("phone_number") + /** + * Returns the raw JSON value of [firstName]. + * + * Unlike [firstName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("first_name") + @ExcludeMissing + fun _firstName(): JsonField = firstName + + /** + * Returns the raw JSON value of [lastName]. + * + * Unlike [lastName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("last_name") + @ExcludeMissing + fun _lastName(): JsonField = lastName + /** * Returns the raw JSON value of [address]. * @@ -1589,16 +1613,6 @@ private constructor( */ @JsonProperty("email") @ExcludeMissing fun _email(): JsonField = email - /** - * Returns the raw JSON value of [firstName]. - * - * Unlike [firstName], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("first_name") - @ExcludeMissing - fun _firstName(): JsonField = firstName - /** * Returns the raw JSON value of [governmentId]. * @@ -1609,16 +1623,6 @@ private constructor( @ExcludeMissing fun _governmentId(): JsonField = governmentId - /** - * Returns the raw JSON value of [lastName]. - * - * Unlike [lastName], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("last_name") - @ExcludeMissing - fun _lastName(): JsonField = lastName - /** * Returns the raw JSON value of [phoneNumber]. * @@ -1644,45 +1648,75 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [KybIndividual]. + * Returns a mutable builder for constructing an instance of + * [KybDelegatedIndividual]. * * The following fields are required: * ```java - * .address() - * .dob() - * .email() * .firstName() - * .governmentId() * .lastName() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [KybIndividual]. */ + /** A builder for [KybDelegatedIndividual]. */ class Builder internal constructor() { - private var address: JsonField
? = null - private var dob: JsonField? = null - private var email: JsonField? = null private var firstName: JsonField? = null - private var governmentId: JsonField? = null private var lastName: JsonField? = null + private var address: JsonField
= JsonMissing.of() + private var dob: JsonField = JsonMissing.of() + private var email: JsonField = JsonMissing.of() + private var governmentId: JsonField = JsonMissing.of() private var phoneNumber: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(kybIndividual: KybIndividual) = apply { - address = kybIndividual.address - dob = kybIndividual.dob - email = kybIndividual.email - firstName = kybIndividual.firstName - governmentId = kybIndividual.governmentId - lastName = kybIndividual.lastName - phoneNumber = kybIndividual.phoneNumber - additionalProperties = kybIndividual.additionalProperties.toMutableMap() + internal fun from(kybDelegatedIndividual: KybDelegatedIndividual) = apply { + firstName = kybDelegatedIndividual.firstName + lastName = kybDelegatedIndividual.lastName + address = kybDelegatedIndividual.address + dob = kybDelegatedIndividual.dob + email = kybDelegatedIndividual.email + governmentId = kybDelegatedIndividual.governmentId + phoneNumber = kybDelegatedIndividual.phoneNumber + additionalProperties = + kybDelegatedIndividual.additionalProperties.toMutableMap() } + /** + * Individual's first name, as it appears on government-issued identity + * documents. + */ + fun firstName(firstName: String) = firstName(JsonField.of(firstName)) + + /** + * Sets [Builder.firstName] to an arbitrary JSON value. + * + * You should usually call [Builder.firstName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun firstName(firstName: JsonField) = apply { + this.firstName = firstName + } + + /** + * Individual's last name, as it appears on government-issued identity + * documents. + */ + fun lastName(lastName: String) = lastName(JsonField.of(lastName)) + + /** + * Sets [Builder.lastName] to an arbitrary JSON value. + * + * You should usually call [Builder.lastName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun lastName(lastName: JsonField) = apply { this.lastName = lastName } + /** * Individual's current address - PO boxes, UPS drops, and FedEx drops are not * acceptable; APO/FPO are acceptable. Only USA addresses are currently @@ -1727,23 +1761,6 @@ private constructor( */ fun email(email: JsonField) = apply { this.email = email } - /** - * Individual's first name, as it appears on government-issued identity - * documents. - */ - fun firstName(firstName: String) = firstName(JsonField.of(firstName)) - - /** - * Sets [Builder.firstName] to an arbitrary JSON value. - * - * You should usually call [Builder.firstName] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun firstName(firstName: JsonField) = apply { - this.firstName = firstName - } - /** * Government-issued identification number (required for identity verification * and compliance with banking regulations). Social Security Numbers (SSN) and @@ -1764,21 +1781,6 @@ private constructor( this.governmentId = governmentId } - /** - * Individual's last name, as it appears on government-issued identity - * documents. - */ - fun lastName(lastName: String) = lastName(JsonField.of(lastName)) - - /** - * Sets [Builder.lastName] to an arbitrary JSON value. - * - * You should usually call [Builder.lastName] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun lastName(lastName: JsonField) = apply { this.lastName = lastName } - /** Individual's phone number, entered in E.164 format. */ fun phoneNumber(phoneNumber: String) = phoneNumber(JsonField.of(phoneNumber)) @@ -1816,30 +1818,26 @@ private constructor( } /** - * Returns an immutable instance of [KybIndividual]. + * Returns an immutable instance of [KybDelegatedIndividual]. * * Further updates to this [Builder] will not mutate the returned instance. * * The following fields are required: * ```java - * .address() - * .dob() - * .email() * .firstName() - * .governmentId() * .lastName() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): KybIndividual = - KybIndividual( - checkRequired("address", address), - checkRequired("dob", dob), - checkRequired("email", email), + fun build(): KybDelegatedIndividual = + KybDelegatedIndividual( checkRequired("firstName", firstName), - checkRequired("governmentId", governmentId), checkRequired("lastName", lastName), + address, + dob, + email, + governmentId, phoneNumber, additionalProperties.toMutableMap(), ) @@ -1847,17 +1845,17 @@ private constructor( private var validated: Boolean = false - fun validate(): KybIndividual = apply { + fun validate(): KybDelegatedIndividual = apply { if (validated) { return@apply } - address().validate() + firstName() + lastName() + address().ifPresent { it.validate() } dob() email() - firstName() governmentId() - lastName() phoneNumber() validated = true } @@ -1878,12 +1876,12 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (address.asKnown().getOrNull()?.validity() ?: 0) + + (if (firstName.asKnown().isPresent) 1 else 0) + + (if (lastName.asKnown().isPresent) 1 else 0) + + (address.asKnown().getOrNull()?.validity() ?: 0) + (if (dob.asKnown().isPresent) 1 else 0) + (if (email.asKnown().isPresent) 1 else 0) + - (if (firstName.asKnown().isPresent) 1 else 0) + (if (governmentId.asKnown().isPresent) 1 else 0) + - (if (lastName.asKnown().isPresent) 1 else 0) + (if (phoneNumber.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -1891,25 +1889,25 @@ private constructor( return true } - return other is KybIndividual && + return other is KybDelegatedIndividual && + firstName == other.firstName && + lastName == other.lastName && address == other.address && dob == other.dob && email == other.email && - firstName == other.firstName && governmentId == other.governmentId && - lastName == other.lastName && phoneNumber == other.phoneNumber && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { Objects.hash( + firstName, + lastName, address, dob, email, - firstName, governmentId, - lastName, phoneNumber, additionalProperties, ) @@ -1918,7 +1916,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "KybIndividual{address=$address, dob=$dob, email=$email, firstName=$firstName, governmentId=$governmentId, lastName=$lastName, phoneNumber=$phoneNumber, additionalProperties=$additionalProperties}" + "KybDelegatedIndividual{firstName=$firstName, lastName=$lastName, address=$address, dob=$dob, email=$email, governmentId=$governmentId, phoneNumber=$phoneNumber, additionalProperties=$additionalProperties}" } /** Specifies the type of KYB workflow to run. */ diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderUploadDocumentParams.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderUploadDocumentParams.kt index 966dfb2f..caf308a7 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderUploadDocumentParams.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/AccountHolderUploadDocumentParams.kt @@ -28,7 +28,7 @@ import kotlin.jvm.optionals.getOrNull * * This endpoint is only valid for evaluations in a `PENDING_DOCUMENT` state. * - * Uploaded images must either be a `jpg` or `png` file, and each must be less than 15 MiB. Once + * Supported file types include `jpg`, `png`, and `pdf`. Each file must be less than 15 MiB. Once * both required uploads have been successfully completed, your document will be run through KYC * verification. * 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 5e8af9ff..77673950 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 @@ -3698,6 +3698,7 @@ private constructor( private val creditor: JsonField, private val debtor: JsonField, private val messageId: JsonField, + private val remittanceInformation: JsonField, private val additionalProperties: MutableMap, ) { @@ -3718,7 +3719,18 @@ private constructor( @JsonProperty("message_id") @ExcludeMissing messageId: JsonField = JsonMissing.of(), - ) : this(wireMessageType, wireNetwork, creditor, debtor, messageId, mutableMapOf()) + @JsonProperty("remittance_information") + @ExcludeMissing + remittanceInformation: JsonField = JsonMissing.of(), + ) : this( + wireMessageType, + wireNetwork, + creditor, + debtor, + messageId, + remittanceInformation, + mutableMapOf(), + ) /** * Type of wire message @@ -3759,6 +3771,15 @@ private constructor( */ fun messageId(): Optional = messageId.getOptional("message_id") + /** + * Payment details or invoice reference + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun remittanceInformation(): Optional = + remittanceInformation.getOptional("remittance_information") + /** * Returns the raw JSON value of [wireMessageType]. * @@ -3808,6 +3829,16 @@ private constructor( @ExcludeMissing fun _messageId(): JsonField = messageId + /** + * Returns the raw JSON value of [remittanceInformation]. + * + * Unlike [remittanceInformation], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("remittance_information") + @ExcludeMissing + fun _remittanceInformation(): JsonField = remittanceInformation + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -3842,6 +3873,7 @@ private constructor( private var creditor: JsonField = JsonMissing.of() private var debtor: JsonField = JsonMissing.of() private var messageId: JsonField = JsonMissing.of() + private var remittanceInformation: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -3851,6 +3883,7 @@ private constructor( creditor = wireMethodAttributes.creditor debtor = wireMethodAttributes.debtor messageId = wireMethodAttributes.messageId + remittanceInformation = wireMethodAttributes.remittanceInformation additionalProperties = wireMethodAttributes.additionalProperties.toMutableMap() } @@ -3931,6 +3964,28 @@ private constructor( */ fun messageId(messageId: JsonField) = apply { this.messageId = messageId } + /** Payment details or invoice reference */ + fun remittanceInformation(remittanceInformation: String?) = + remittanceInformation(JsonField.ofNullable(remittanceInformation)) + + /** + * Alias for calling [Builder.remittanceInformation] with + * `remittanceInformation.orElse(null)`. + */ + fun remittanceInformation(remittanceInformation: Optional) = + remittanceInformation(remittanceInformation.getOrNull()) + + /** + * Sets [Builder.remittanceInformation] to an arbitrary JSON value. + * + * You should usually call [Builder.remittanceInformation] with a well-typed + * [String] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun remittanceInformation(remittanceInformation: JsonField) = apply { + this.remittanceInformation = remittanceInformation + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -3973,6 +4028,7 @@ private constructor( creditor, debtor, messageId, + remittanceInformation, additionalProperties.toMutableMap(), ) } @@ -3989,6 +4045,7 @@ private constructor( creditor().ifPresent { it.validate() } debtor().ifPresent { it.validate() } messageId() + remittanceInformation() validated = true } @@ -4012,7 +4069,8 @@ private constructor( (wireNetwork.asKnown().getOrNull()?.validity() ?: 0) + (creditor.asKnown().getOrNull()?.validity() ?: 0) + (debtor.asKnown().getOrNull()?.validity() ?: 0) + - (if (messageId.asKnown().isPresent) 1 else 0) + (if (messageId.asKnown().isPresent) 1 else 0) + + (if (remittanceInformation.asKnown().isPresent) 1 else 0) /** Type of wire transfer */ class WireNetwork @@ -4158,6 +4216,7 @@ private constructor( creditor == other.creditor && debtor == other.debtor && messageId == other.messageId && + remittanceInformation == other.remittanceInformation && additionalProperties == other.additionalProperties } @@ -4168,6 +4227,7 @@ private constructor( creditor, debtor, messageId, + remittanceInformation, additionalProperties, ) } @@ -4175,7 +4235,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "WireMethodAttributes{wireMessageType=$wireMessageType, wireNetwork=$wireNetwork, creditor=$creditor, debtor=$debtor, messageId=$messageId, additionalProperties=$additionalProperties}" + "WireMethodAttributes{wireMessageType=$wireMessageType, wireNetwork=$wireNetwork, creditor=$creditor, debtor=$debtor, messageId=$messageId, remittanceInformation=$remittanceInformation, additionalProperties=$additionalProperties}" } } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/AccountHolderServiceAsync.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/AccountHolderServiceAsync.kt index 81d88ec7..e969e718 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/AccountHolderServiceAsync.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/AccountHolderServiceAsync.kt @@ -351,9 +351,9 @@ interface AccountHolderServiceAsync { * * This endpoint is only valid for evaluations in a `PENDING_DOCUMENT` state. * - * Uploaded images must either be a `jpg` or `png` file, and each must be less than 15 MiB. Once - * both required uploads have been successfully completed, your document will be run through KYC - * verification. + * Supported file types include `jpg`, `png`, and `pdf`. Each file must be less than 15 MiB. + * Once both required uploads have been successfully completed, your document will be run + * through KYC verification. * * If you have registered a webhook, you will receive evaluation updates for any document * submission evaluations, as well as for any failed document uploads. diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/CardServiceAsyncImpl.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/CardServiceAsyncImpl.kt index c0f754b8..dd8e6417 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/CardServiceAsyncImpl.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/services/async/CardServiceAsyncImpl.kt @@ -621,7 +621,7 @@ class CardServiceAsyncImpl internal constructor(private val clientOptions: Clien return buildString { append(clientOptions.baseUrl()) if (!endsWith("/")) append("/") - append("embed/card") + append("v1/embed/card") append("?embed_request=") append(URLEncoder.encode(embed_request, "UTF-8")) append("&hmac=") diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/AccountHolderService.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/AccountHolderService.kt index f81503f2..743f091e 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/AccountHolderService.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/AccountHolderService.kt @@ -339,9 +339,9 @@ interface AccountHolderService { * * This endpoint is only valid for evaluations in a `PENDING_DOCUMENT` state. * - * Uploaded images must either be a `jpg` or `png` file, and each must be less than 15 MiB. Once - * both required uploads have been successfully completed, your document will be run through KYC - * verification. + * Supported file types include `jpg`, `png`, and `pdf`. Each file must be less than 15 MiB. + * Once both required uploads have been successfully completed, your document will be run + * through KYC verification. * * If you have registered a webhook, you will receive evaluation updates for any document * submission evaluations, as well as for any failed document uploads. diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/CardServiceImpl.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/CardServiceImpl.kt index 9a1991ad..f290bdeb 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/CardServiceImpl.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/services/blocking/CardServiceImpl.kt @@ -556,7 +556,7 @@ class CardServiceImpl internal constructor(private val clientOptions: ClientOpti return buildString { append(clientOptions.baseUrl()) if (!endsWith("/")) append("/") - append("embed/card") + append("v1/embed/card") append("?embed_request=") append(URLEncoder.encode(embed_request, "UTF-8")) append("&hmac=") diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ClientOptionsTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ClientOptionsTest.kt index b2e10457..65c82ba6 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/core/ClientOptionsTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/core/ClientOptionsTest.kt @@ -16,6 +16,29 @@ internal class ClientOptionsTest { private val httpClient = mock() + @Test + fun putHeader_canOverwriteDefaultHeader() { + val clientOptions = + ClientOptions.builder() + .httpClient(httpClient) + .putHeader("User-Agent", "My User Agent") + .apiKey("My Lithic API Key") + .build() + + assertThat(clientOptions.headers.values("User-Agent")).containsExactly("My User Agent") + } + + @Test + fun toBuilder_apiKeyAuthCanBeUpdated() { + var clientOptions = + ClientOptions.builder().httpClient(httpClient).apiKey("My Lithic API Key").build() + + clientOptions = clientOptions.toBuilder().apiKey("another My Lithic API Key").build() + + assertThat(clientOptions.headers.values("Authorization")) + .containsExactly("another My Lithic API Key") + } + @Test fun toBuilder_whenOriginalClientOptionsGarbageCollected_doesNotCloseOriginalClient() { var clientOptions = diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/core/http/RetryingHttpClientTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/core/http/RetryingHttpClientTest.kt index 9da44782..1e6ef7f0 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/core/http/RetryingHttpClientTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/core/http/RetryingHttpClientTest.kt @@ -400,9 +400,9 @@ internal class RetryingHttpClientTest { assertThat(sleeper.durations).hasSize(3) // retries=1: 0.5s * [0.75, 1.0] assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) - // retries=2: 1.0s * [0.75, 1.0] + // retries=2: 1s * [0.75, 1.0] assertThat(sleeper.durations[1]).isBetween(Duration.ofMillis(750), Duration.ofMillis(1000)) - // retries=3: 2.0s * [0.75, 1.0] + // retries=3: 2s * [0.75, 1.0] assertThat(sleeper.durations[2]).isBetween(Duration.ofMillis(1500), Duration.ofMillis(2000)) assertNoResponseLeaks() } @@ -427,9 +427,9 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(503) verify(7, postRequestedFor(urlPathEqualTo("/something"))) assertThat(sleeper.durations).hasSize(6) - // retries=5: min(0.5 * 2^4, 8) = 8.0s * [0.75, 1.0] + // retries=5: backoff hits the 8s cap * [0.75, 1.0] assertThat(sleeper.durations[4]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) - // retries=6: min(0.5 * 2^5, 8) = min(16, 8) = 8.0s * [0.75, 1.0] (capped) + // retries=6: still capped at 8s * [0.75, 1.0] assertThat(sleeper.durations[5]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) assertNoResponseLeaks() }