Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions openapi/SOURCE.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"verification.json": {
"url": "https://docs.didit.me/openapi-25.json",
"sha256": "12b2fdb05572755d61b93791f6964b7d883ba7b20f7ea9b31543903b6edab8a9",
"fetched_at": "2026-10-29T06:37:04Z"
"sha256": "c6707376c9bcdf636c1fd5452f61955c2c5ca304cce6a1ea8018d4c087fe8914",
"fetched_at": "2026-11-01T06:31:24Z"
},
"account.json": {
"url": "https://docs.didit.me/openapi-auth.json",
"sha256": "ae1b5e07df822fe93cae27a9eaa0790948069352c9d98c87eecf7efd644c92cb",
"fetched_at": "2026-10-29T06:37:04Z"
"sha256": "5b45b1896ef3107dd9a601c76d9ba35761bae5f04ac731b6c27876603903bf05",
"fetched_at": "2026-11-01T06:31:24Z"
},
"webhook-vectors.json": {
"generator": "product-automations scripts/server-sdks/make_vectors.py (seeded 2026-10-17)",
Expand Down
295 changes: 272 additions & 23 deletions openapi/account.json

Large diffs are not rendered by default.

31,497 changes: 24,982 additions & 6,515 deletions openapi/verification.json

Large diffs are not rendered by default.

179 changes: 179 additions & 0 deletions src/main/java/me/didit/resources/AnalyticsResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import me.didit.core.Responses;
import me.didit.types.AnalyticsRetrieveParams;
import me.didit.types.AnalyticsRetrieveResponse;
import me.didit.types.AnalyticsRetrieveTodayParams;
import me.didit.types.ApplicationAnalyticsToday;

/** The {@code analytics} resource: {@code client.analytics()}. */
public final class AnalyticsResource {
Expand Down Expand Up @@ -120,6 +122,93 @@ public CompletableFuture<AnalyticsRetrieveResponse> retrieveAsync() {
return client.executeAsync(retrieveRequest(AnalyticsRetrieveParams.builder().build()), RequestOptions.none(), RETRIEVE_RESPONSE).thenApply(RawResponse::data);
}

/**
* Get today's verifications by hour
*
* <p>Today's user verification (KYC) sessions, from local midnight in <code>tz</code>, counted per local hour they were created in, next to the same hours of the same weekday one week before, and split by the outcome each one holds now: approved, in review or declined. This is the volume card of the Business Console's Home.
*
* <p><code>total</code> is today so far. <code>previous_total_so_far</code> counts the comparison day only up to the same local time, so a change between them compares the same part of both days. The hours still to come today are <code>0</code>. A day on which the clocks change has 23 or 25 hours: the missing hour stays <code>0</code> and the repeated hour holds both.
*
* <p>{@code GET /v3/organization/{organization_id}/application/{application_id}/analytics/today/}
* <p>Application scoped: the organization and application ids come from the client options.
*
* @param params the request parameters
* @param options per-request options that override the client options
* @return the response body
*/
public ApplicationAnalyticsToday retrieveToday(AnalyticsRetrieveTodayParams params, RequestOptions options) {
return client.execute(retrieveTodayRequest(params), options, RETRIEVE_TODAY_RESPONSE).data();
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)}.
*
* @param params the request parameters
* @param options per-request options
* @return a future completed with the result
*/
public CompletableFuture<ApplicationAnalyticsToday> retrieveTodayAsync(AnalyticsRetrieveTodayParams params, RequestOptions options) {
return client.executeAsync(retrieveTodayRequest(params), options, RETRIEVE_TODAY_RESPONSE).thenApply(RawResponse::data);
}

/**
* Same as {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)}, with the client's options.
*
* @param params the request parameters
* @return the result
*/
public ApplicationAnalyticsToday retrieveToday(AnalyticsRetrieveTodayParams params) {
return client.execute(retrieveTodayRequest(params), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE).data();
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)}, with the client's options.
*
* @param params the request parameters
* @return a future completed with the result
*/
public CompletableFuture<ApplicationAnalyticsToday> retrieveTodayAsync(AnalyticsRetrieveTodayParams params) {
return client.executeAsync(retrieveTodayRequest(params), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE).thenApply(RawResponse::data);
}

/**
* Same as {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)}, without parameters.
*
* @param options per-request options
* @return the result
*/
public ApplicationAnalyticsToday retrieveToday(RequestOptions options) {
return client.execute(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), options, RETRIEVE_TODAY_RESPONSE).data();
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)}, without parameters.
*
* @param options per-request options
* @return a future completed with the result
*/
public CompletableFuture<ApplicationAnalyticsToday> retrieveTodayAsync(RequestOptions options) {
return client.executeAsync(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), options, RETRIEVE_TODAY_RESPONSE).thenApply(RawResponse::data);
}

/**
* Same as {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)}, without parameters, with the client's options.
*
* @return the result
*/
public ApplicationAnalyticsToday retrieveToday() {
return client.execute(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE).data();
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)}, without parameters, with the client's options.
*
* @return a future completed with the result
*/
public CompletableFuture<ApplicationAnalyticsToday> retrieveTodayAsync() {
return client.executeAsync(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE).thenApply(RawResponse::data);
}

private static final ResponseHandler<AnalyticsRetrieveResponse> RETRIEVE_RESPONSE = Responses.json(Conv.union(AnalyticsRetrieveResponse::fromJson));

private static ApiRequest retrieveRequest(AnalyticsRetrieveParams params) {
Expand All @@ -130,6 +219,16 @@ private static ApiRequest retrieveRequest(AnalyticsRetrieveParams params) {
.build();
}

private static final ResponseHandler<ApplicationAnalyticsToday> RETRIEVE_TODAY_RESPONSE = Responses.json(Conv.model(ApplicationAnalyticsToday::fromJson));

private static ApiRequest retrieveTodayRequest(AnalyticsRetrieveTodayParams params) {
return ApiRequest.builder("GET", "/v3/organization/{organization_id}/application/{application_id}/analytics/today/")
.applicationScoped()
.params(params)
.queryFields("tz")
.build();
}

/** The {@code analytics} operations returning {@link RawResponse}. */
public static final class WithRawResponse {
private final ApiClient client;
Expand Down Expand Up @@ -217,5 +316,85 @@ public RawResponse<AnalyticsRetrieveResponse> retrieve() {
public CompletableFuture<RawResponse<AnalyticsRetrieveResponse>> retrieveAsync() {
return client.executeAsync(retrieveRequest(AnalyticsRetrieveParams.builder().build()), RequestOptions.none(), RETRIEVE_RESPONSE);
}

/**
* {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response.
*
* @param params the request parameters
* @param options per-request options
* @return the result
*/
public RawResponse<ApplicationAnalyticsToday> retrieveToday(AnalyticsRetrieveTodayParams params, RequestOptions options) {
return client.execute(retrieveTodayRequest(params), options, RETRIEVE_TODAY_RESPONSE);
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response.
*
* @param params the request parameters
* @param options per-request options
* @return a future completed with the result
*/
public CompletableFuture<RawResponse<ApplicationAnalyticsToday>> retrieveTodayAsync(AnalyticsRetrieveTodayParams params, RequestOptions options) {
return client.executeAsync(retrieveTodayRequest(params), options, RETRIEVE_TODAY_RESPONSE);
}

/**
* {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response, with the client's options.
*
* @param params the request parameters
* @return the result
*/
public RawResponse<ApplicationAnalyticsToday> retrieveToday(AnalyticsRetrieveTodayParams params) {
return client.execute(retrieveTodayRequest(params), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE);
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response, with the client's options.
*
* @param params the request parameters
* @return a future completed with the result
*/
public CompletableFuture<RawResponse<ApplicationAnalyticsToday>> retrieveTodayAsync(AnalyticsRetrieveTodayParams params) {
return client.executeAsync(retrieveTodayRequest(params), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE);
}

/**
* {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response, without parameters.
*
* @param options per-request options
* @return the result
*/
public RawResponse<ApplicationAnalyticsToday> retrieveToday(RequestOptions options) {
return client.execute(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), options, RETRIEVE_TODAY_RESPONSE);
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response, without parameters.
*
* @param options per-request options
* @return a future completed with the result
*/
public CompletableFuture<RawResponse<ApplicationAnalyticsToday>> retrieveTodayAsync(RequestOptions options) {
return client.executeAsync(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), options, RETRIEVE_TODAY_RESPONSE);
}

/**
* {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response, without parameters, with the client's options.
*
* @return the result
*/
public RawResponse<ApplicationAnalyticsToday> retrieveToday() {
return client.execute(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE);
}

/**
* Asynchronous {@link #retrieveToday(AnalyticsRetrieveTodayParams, RequestOptions)} with the raw response, without parameters, with the client's options.
*
* @return a future completed with the result
*/
public CompletableFuture<RawResponse<ApplicationAnalyticsToday>> retrieveTodayAsync() {
return client.executeAsync(retrieveTodayRequest(AnalyticsRetrieveTodayParams.builder().build()), RequestOptions.none(), RETRIEVE_TODAY_RESPONSE);
}
}
}
4 changes: 3 additions & 1 deletion src/main/java/me/didit/resources/BankResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public WithRawResponse withRawResponse() {
/**
* Check a bank account
*
* <p><b>Not available in production yet.</b> Bank Verification is switched off in production, so until it is switched on this endpoint answers <code>404</code> with <code>bank_verification_not_available</code>. Do not build on it yet. The rest of this description is what the endpoint does once it is available.
*
* <p>Check that a bank account belongs to the person or company you name, before you send money to it. No session and no sign-in: send the name and the account, read the result. It is the [account check](/core-technology/bank-verification/account-check) of the Bank Verification step, run from your backend.
*
* <p><b>What you send.</b> The account's <code>country</code> (ISO 3166-1 alpha-3), the <code>account</code> the way that country writes it, and the <code>holder</code> name: <code>full_name</code> for a person or <code>business_name</code> for a company. A business name checks a business account.
Expand All @@ -44,7 +46,7 @@ public WithRawResponse withRawResponse() {
*
* <p><b>Every request is a new check.</b> There is no idempotency key and no endpoint to read a check back, so a retried request runs, and is billed, again. Store the response.
*
* <p><b>Sandbox.</b> A sandbox key calls no bank and is charged nothing. The last 4 characters of the IBAN, else of the account number, choose the answer: <code>0001</code> a <code>close_match</code> with a <code>holder_name</code>, <code>0002</code> a <code>close_match</code> without one, <code>0003</code> and <code>0006</code> a <code>no_match</code>, <code>0004</code> <code>cannot_verify</code>, <code>0005</code> a <code>503</code> and <code>0009</code> a <code>400</code>. Any other ending is a <code>match</code>.
* <p><b>Sandbox.</b> Where Bank Verification is available, a sandbox key calls no bank and is charged nothing. The last 4 characters of the IBAN, else of the account number, choose the answer: <code>0001</code> a <code>close_match</code> with a <code>holder_name</code>, <code>0002</code> a <code>close_match</code> without one, <code>0003</code> and <code>0006</code> a <code>no_match</code>, <code>0004</code> <code>cannot_verify</code>, <code>0005</code> a <code>503</code> and <code>0009</code> a <code>400</code>. Any other ending is a <code>match</code>.
*
* <p><b>API keys.</b> A scoped API key needs write access to sessions.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public WithRawResponse withRawResponse() {
*
* <p><b>How it works.</b> Send the document's <code>front_image</code> (required) and, for two-sided documents, the <code>back_image</code>. Upload uncropped photos with all four corners of the document visible — the service detects, aligns, and crops the document itself, so do not pre-crop. The document is classified automatically (you never declare the country or document type), the visual zone is read with OCR, and the MRZ and any barcodes are decoded. Cross-checks then validate dates, number formats, and MRZ check digits, and compare the visual zone against the MRZ. With <code>perform_document_liveness=true</code>, the images are additionally screened for screen replays, printed copies, and portrait manipulation.
*
* <p><b>Decision logic.</b> <code>status</code> is <code>Approved</code> unless at least one warning resolves to a decline. Fraud and hard-failure risks always decline: <code>DOCUMENT_EXPIRED</code>, <code>SCREEN_CAPTURE_DETECTED</code>, <code>PRINTED_COPY_DETECTED</code>, <code>PORTRAIT_MANIPULATION_DETECTED</code>, <code>PUBLIC_DOCUMENT_IMAGE_DETECTED</code>, plus extraction failures (<code>NAME_NOT_DETECTED</code>, <code>DATE_OF_BIRTH_NOT_DETECTED</code>, <code>DOCUMENT_NUMBER_NOT_DETECTED</code>). (<code>PORTRAIT_IMAGE_NOT_DETECTED</code>, <code>COULD_NOT_DETECT_DOCUMENT_TYPE</code>, <code>INVALID_DATE</code>, and <code>MRZ_NOT_DETECTED</code> exist in workflow sessions but are never produced by this standalone endpoint.) Three risk groups are configurable per request via <code>invalid_mrz_action</code>, <code>inconsistent_data_action</code>, and <code>expiration_date_not_detected_action</code> (<code>DECLINE</code> or <code>NO_ACTION</code>). All other warnings (e.g. <code>POSSIBLE_DUPLICATED_USER</code>) are informational and never decline on their own. When <code>perform_document_liveness=true</code> (the default) and the forgery check returns no usable score — the provider failed, answered non-200, or answered HTTP 200 with <code>status="ERR"</code> - the call returns <code>200</code> with <code>status: "In Review"</code> and a <code>DOCUMENT_LIVENESS_NOT_COMPUTED</code> warning (<code>log_type: "warning"</code>) instead of <code>Approved</code>: a check that did not run is not evidence that the document is genuine. This escalation is not configurable and never overrides a <code>Declined</code>; with <code>perform_document_liveness=false</code> the check is skipped and the status follows the remaining warnings as before. A document that cannot be processed at all returns <code>400</code> with <code>{"error": "COULD_NOT_RECOGNIZE_DOCUMENT"}</code>; a readable but problematic document returns <code>200</code> with <code>status: "Declined"</code> — always inspect <code>id_verification.status</code> and <code>id_verification.warnings</code>, not just the HTTP code.
* <p><b>Decision logic.</b> <code>status</code> is <code>Approved</code> unless at least one warning resolves to a decline. Fraud and hard-failure risks always decline: <code>DOCUMENT_EXPIRED</code>, <code>SCREEN_CAPTURE_DETECTED</code>, <code>PRINTED_COPY_DETECTED</code>, <code>PORTRAIT_MANIPULATION_DETECTED</code>, <code>PUBLIC_DOCUMENT_IMAGE_DETECTED</code>, plus extraction failures (<code>NAME_NOT_DETECTED</code>, <code>DATE_OF_BIRTH_NOT_DETECTED</code>, <code>DOCUMENT_NUMBER_NOT_DETECTED</code>). (<code>PORTRAIT_IMAGE_NOT_DETECTED</code>, <code>INVALID_DATE</code>, and <code>MRZ_NOT_DETECTED</code> exist in workflow sessions but are never produced by this standalone endpoint. <code>COULD_NOT_DETECT_DOCUMENT_TYPE</code> is returned here when the front image does not match a known official document design with high confidence, and declines the request.) Three risk groups are configurable per request via <code>invalid_mrz_action</code>, <code>inconsistent_data_action</code>, and <code>expiration_date_not_detected_action</code> (<code>DECLINE</code> or <code>NO_ACTION</code>). All other warnings (e.g. <code>POSSIBLE_DUPLICATED_USER</code>) are informational and never decline on their own. When <code>perform_document_liveness=true</code> (the default) and the forgery check returns no usable score — the provider failed, answered non-200, or answered HTTP 200 with <code>status="ERR"</code> - the call returns <code>200</code> with <code>status: "In Review"</code> and a <code>DOCUMENT_LIVENESS_NOT_COMPUTED</code> warning (<code>log_type: "warning"</code>) instead of <code>Approved</code>: a check that did not run is not evidence that the document is genuine. This escalation is not configurable and never overrides a <code>Declined</code>; with <code>perform_document_liveness=false</code> the check is skipped and the status follows the remaining warnings as before. A document that cannot be processed at all returns <code>400</code> with <code>{"error": "COULD_NOT_RECOGNIZE_DOCUMENT"}</code>; a readable but problematic document returns <code>200</code> with <code>status: "Declined"</code> — always inspect <code>id_verification.status</code> and <code>id_verification.warnings</code>, not just the HTTP code.
*
* <p><b>Billing.</b> Each <code>200</code> response consumes one ID Verification API credit (paid from your plan credit or top-up balance). When the organization's balance cannot cover the call, the endpoint returns <code>403</code> with the not-enough-credits error before any image processing.
*
Expand Down
Loading