From 524243a641cfb439443592613422465cefd1f8d3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 15:48:54 +0000 Subject: [PATCH 1/2] feat(api): manual updates --- .stats.yml | 6 +- api.md | 82 ++- src/index.ts | 46 +- src/resources/index.ts | 10 +- src/resources/intel.ts | 3 + src/resources/intel/index.ts | 4 + src/resources/intel/intel.ts | 15 + src/resources/intel/kyc.ts | 190 +++++ src/resources/notify.ts | 87 +++ src/resources/shared.ts | 87 +++ src/resources/verification-management.ts | 230 +----- .../verification-management/index.ts | 20 + .../verification-management/sandbox.ts | 144 ++++ .../verification-management.ts | 251 +++++++ src/resources/verification.ts | 558 +------------- src/resources/verification/index.ts | 10 + src/resources/verification/phone.ts | 3 + src/resources/verification/phone/history.ts | 681 ++++++++++++++++++ src/resources/verification/phone/index.ts | 12 + src/resources/verification/phone/phone.ts | 31 + src/resources/verification/verification.ts | 465 ++++++++++++ src/resources/watch.ts | 321 +++++---- tests/api-resources/intel/kyc.test.ts | 22 + tests/api-resources/notify.test.ts | 25 + .../verification-management/sandbox.test.ts | 70 ++ .../verification-management.test.ts | 0 .../verification/phone/history.test.ts | 72 ++ .../{ => verification}/verification.test.ts | 0 tests/api-resources/watch.test.ts | 36 + 29 files changed, 2539 insertions(+), 942 deletions(-) create mode 100644 src/resources/intel.ts create mode 100644 src/resources/intel/index.ts create mode 100644 src/resources/intel/intel.ts create mode 100644 src/resources/intel/kyc.ts create mode 100644 src/resources/shared.ts create mode 100644 src/resources/verification-management/index.ts create mode 100644 src/resources/verification-management/sandbox.ts create mode 100644 src/resources/verification-management/verification-management.ts create mode 100644 src/resources/verification/index.ts create mode 100644 src/resources/verification/phone.ts create mode 100644 src/resources/verification/phone/history.ts create mode 100644 src/resources/verification/phone/index.ts create mode 100644 src/resources/verification/phone/phone.ts create mode 100644 src/resources/verification/verification.ts create mode 100644 tests/api-resources/intel/kyc.test.ts create mode 100644 tests/api-resources/verification-management/sandbox.test.ts rename tests/api-resources/{ => verification-management}/verification-management.test.ts (100%) create mode 100644 tests/api-resources/verification/phone/history.test.ts rename tests/api-resources/{ => verification}/verification.test.ts (100%) diff --git a/.stats.yml b/.stats.yml index b57e87a..cce5f55 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 19 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude/prelude-86fc45f417e6468f6a6087f9e35b264b0a350e31385bc078a2027a1f1abd1d15.yml +configured_endpoints: 27 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude/prelude-33b70f86404b99046db5c61d3142b149dd7dec7eefe5e62ff3b397c7274aa5dc.yml openapi_spec_hash: fb72aba38ec55a3b6b5162c9f5b4228d -config_hash: 3dbe79c14ecd9a153418249f9155d159 +config_hash: 707d65d2f456a2b5ba5b2c565b60128a diff --git a/api.md b/api.md index b163185..fb13e1e 100644 --- a/api.md +++ b/api.md @@ -1,3 +1,10 @@ +# Shared + +Types: + +- Signals +- Target + # Lookup Types: @@ -17,6 +24,7 @@ Types: - NotifyListSubscriptionConfigsResponse - NotifyListSubscriptionPhoneNumberEventsResponse - NotifyListSubscriptionPhoneNumbersResponse +- NotifyReplyResponse - NotifySendResponse - NotifySendBatchResponse @@ -27,6 +35,7 @@ Methods: - client.notify.listSubscriptionConfigs({ ...params }) -> NotifyListSubscriptionConfigsResponse - client.notify.listSubscriptionPhoneNumberEvents(configId, phoneNumber, { ...params }) -> NotifyListSubscriptionPhoneNumberEventsResponse - client.notify.listSubscriptionPhoneNumbers(configId, { ...params }) -> NotifyListSubscriptionPhoneNumbersResponse +- client.notify.reply({ ...params }) -> NotifyReplyResponse - client.notify.send({ ...params }) -> NotifySendResponse - client.notify.sendBatch({ ...params }) -> NotifySendBatchResponse @@ -44,42 +53,87 @@ Methods: Types: -- VerificationCreateResponse -- VerificationCheckResponse +- VerificationCreateResponse +- VerificationCheckResponse + +Methods: + +- client.verification.create({ ...params }) -> VerificationCreateResponse +- client.verification.check({ ...params }) -> VerificationCheckResponse + +## Phone + +### History + +Types: + +- PhoneVerificationCarrier +- PhoneVerificationMoney +- PhoneVerificationPsd2Transaction +- HistoryRetrieveResponse +- HistoryListResponse Methods: -- client.verification.create({ ...params }) -> VerificationCreateResponse -- client.verification.check({ ...params }) -> VerificationCheckResponse +- client.verification.phone.history.retrieve(id) -> HistoryRetrieveResponse +- client.verification.phone.history.list({ ...params }) -> HistoryListResponse # VerificationManagement Types: -- VerificationManagementDeletePhoneNumberResponse -- VerificationManagementListPhoneNumbersResponse -- VerificationManagementListSenderIDsResponse -- VerificationManagementSetPhoneNumberResponse -- VerificationManagementSubmitSenderIDResponse +- VerificationManagementDeletePhoneNumberResponse +- VerificationManagementListPhoneNumbersResponse +- VerificationManagementListSenderIDsResponse +- VerificationManagementSetPhoneNumberResponse +- VerificationManagementSubmitSenderIDResponse Methods: -- client.verificationManagement.deletePhoneNumber(action, { ...params }) -> VerificationManagementDeletePhoneNumberResponse -- client.verificationManagement.listPhoneNumbers(action) -> VerificationManagementListPhoneNumbersResponse -- client.verificationManagement.listSenderIds() -> VerificationManagementListSenderIDsResponse -- client.verificationManagement.setPhoneNumber(action, { ...params }) -> VerificationManagementSetPhoneNumberResponse -- client.verificationManagement.submitSenderId({ ...params }) -> VerificationManagementSubmitSenderIDResponse +- client.verificationManagement.deletePhoneNumber(action, { ...params }) -> VerificationManagementDeletePhoneNumberResponse +- client.verificationManagement.listPhoneNumbers(action) -> VerificationManagementListPhoneNumbersResponse +- client.verificationManagement.listSenderIds() -> VerificationManagementListSenderIDsResponse +- client.verificationManagement.setPhoneNumber(action, { ...params }) -> VerificationManagementSetPhoneNumberResponse +- client.verificationManagement.submitSenderId({ ...params }) -> VerificationManagementSubmitSenderIDResponse + +## Sandbox + +Types: + +- SandboxAddPhoneNumberResponse +- SandboxDeletePhoneNumberResponse +- SandboxListPhoneNumbersResponse + +Methods: + +- client.verificationManagement.sandbox.addPhoneNumber({ ...params }) -> SandboxAddPhoneNumberResponse +- client.verificationManagement.sandbox.deletePhoneNumber(phoneNumber) -> SandboxDeletePhoneNumberResponse +- client.verificationManagement.sandbox.listPhoneNumbers() -> SandboxListPhoneNumbersResponse # Watch Types: +- WatchEvaluateResponse - WatchPredictResponse - WatchSendEventsResponse - WatchSendFeedbacksResponse Methods: +- client.watch.evaluate({ ...params }) -> WatchEvaluateResponse - client.watch.predict({ ...params }) -> WatchPredictResponse - client.watch.sendEvents({ ...params }) -> WatchSendEventsResponse - client.watch.sendFeedbacks({ ...params }) -> WatchSendFeedbacksResponse + +# Intel + +## KYC + +Types: + +- KYCMatchResponse + +Methods: + +- client.intel.kyc.match(phone, { ...params }) -> KYCMatchResponse diff --git a/src/index.ts b/src/index.ts index fc7dcd6..e0776c3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,8 @@ import { NotifyListSubscriptionPhoneNumberEventsResponse, NotifyListSubscriptionPhoneNumbersParams, NotifyListSubscriptionPhoneNumbersResponse, + NotifyReplyParams, + NotifyReplyResponse, NotifySendBatchParams, NotifySendBatchResponse, NotifySendParams, @@ -24,12 +26,17 @@ import { } from './resources/notify'; import { Transactional, TransactionalSendParams, TransactionalSendResponse } from './resources/transactional'; import { - Verification, - VerificationCheckParams, - VerificationCheckResponse, - VerificationCreateParams, - VerificationCreateResponse, -} from './resources/verification'; + Watch, + WatchEvaluateParams, + WatchEvaluateResponse, + WatchPredictParams, + WatchPredictResponse, + WatchSendEventsParams, + WatchSendEventsResponse, + WatchSendFeedbacksParams, + WatchSendFeedbacksResponse, +} from './resources/watch'; +import { Intel } from './resources/intel/intel'; import { VerificationManagement, VerificationManagementDeletePhoneNumberParams, @@ -40,16 +47,14 @@ import { VerificationManagementSetPhoneNumberResponse, VerificationManagementSubmitSenderIDParams, VerificationManagementSubmitSenderIDResponse, -} from './resources/verification-management'; +} from './resources/verification-management/verification-management'; import { - Watch, - WatchPredictParams, - WatchPredictResponse, - WatchSendEventsParams, - WatchSendEventsResponse, - WatchSendFeedbacksParams, - WatchSendFeedbacksResponse, -} from './resources/watch'; + Verification, + VerificationCheckParams, + VerificationCheckResponse, + VerificationCreateParams, + VerificationCreateResponse, +} from './resources/verification/verification'; export interface ClientOptions { /** @@ -203,6 +208,7 @@ export class Prelude extends Core.APIClient { * Evaluate email addresses and phone numbers for trustworthiness. */ watch: API.Watch = new API.Watch(this); + intel: API.Intel = new API.Intel(this); /** * Check whether the base URL is set to its default. @@ -257,6 +263,7 @@ Prelude.Transactional = Transactional; Prelude.Verification = Verification; Prelude.VerificationManagement = VerificationManagement; Prelude.Watch = Watch; +Prelude.Intel = Intel; export declare namespace Prelude { export type RequestOptions = Core.RequestOptions; @@ -274,11 +281,13 @@ export declare namespace Prelude { type NotifyListSubscriptionConfigsResponse as NotifyListSubscriptionConfigsResponse, type NotifyListSubscriptionPhoneNumberEventsResponse as NotifyListSubscriptionPhoneNumberEventsResponse, type NotifyListSubscriptionPhoneNumbersResponse as NotifyListSubscriptionPhoneNumbersResponse, + type NotifyReplyResponse as NotifyReplyResponse, type NotifySendResponse as NotifySendResponse, type NotifySendBatchResponse as NotifySendBatchResponse, type NotifyListSubscriptionConfigsParams as NotifyListSubscriptionConfigsParams, type NotifyListSubscriptionPhoneNumberEventsParams as NotifyListSubscriptionPhoneNumberEventsParams, type NotifyListSubscriptionPhoneNumbersParams as NotifyListSubscriptionPhoneNumbersParams, + type NotifyReplyParams as NotifyReplyParams, type NotifySendParams as NotifySendParams, type NotifySendBatchParams as NotifySendBatchParams, }; @@ -311,13 +320,20 @@ export declare namespace Prelude { export { Watch as Watch, + type WatchEvaluateResponse as WatchEvaluateResponse, type WatchPredictResponse as WatchPredictResponse, type WatchSendEventsResponse as WatchSendEventsResponse, type WatchSendFeedbacksResponse as WatchSendFeedbacksResponse, + type WatchEvaluateParams as WatchEvaluateParams, type WatchPredictParams as WatchPredictParams, type WatchSendEventsParams as WatchSendEventsParams, type WatchSendFeedbacksParams as WatchSendFeedbacksParams, }; + + export { Intel as Intel }; + + export type Signals = API.Signals; + export type Target = API.Target; } export { toFile, fileFromPath } from './uploads'; diff --git a/src/resources/index.ts b/src/resources/index.ts index 44dec0d..b35034a 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +export * from './shared'; +export { Intel } from './intel/intel'; export { Lookup, type LookupLookupResponse, type LookupLookupParams } from './lookup'; export { Notify, @@ -8,11 +10,13 @@ export { type NotifyListSubscriptionConfigsResponse, type NotifyListSubscriptionPhoneNumberEventsResponse, type NotifyListSubscriptionPhoneNumbersResponse, + type NotifyReplyResponse, type NotifySendResponse, type NotifySendBatchResponse, type NotifyListSubscriptionConfigsParams, type NotifyListSubscriptionPhoneNumberEventsParams, type NotifyListSubscriptionPhoneNumbersParams, + type NotifyReplyParams, type NotifySendParams, type NotifySendBatchParams, } from './notify'; @@ -23,7 +27,7 @@ export { type VerificationCheckResponse, type VerificationCreateParams, type VerificationCheckParams, -} from './verification'; +} from './verification/verification'; export { VerificationManagement, type VerificationManagementDeletePhoneNumberResponse, @@ -34,12 +38,14 @@ export { type VerificationManagementDeletePhoneNumberParams, type VerificationManagementSetPhoneNumberParams, type VerificationManagementSubmitSenderIDParams, -} from './verification-management'; +} from './verification-management/verification-management'; export { Watch, + type WatchEvaluateResponse, type WatchPredictResponse, type WatchSendEventsResponse, type WatchSendFeedbacksResponse, + type WatchEvaluateParams, type WatchPredictParams, type WatchSendEventsParams, type WatchSendFeedbacksParams, diff --git a/src/resources/intel.ts b/src/resources/intel.ts new file mode 100644 index 0000000..409016b --- /dev/null +++ b/src/resources/intel.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './intel/index'; diff --git a/src/resources/intel/index.ts b/src/resources/intel/index.ts new file mode 100644 index 0000000..9aae2ed --- /dev/null +++ b/src/resources/intel/index.ts @@ -0,0 +1,4 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Intel } from './intel'; +export { KYC, type KYCMatchResponse, type KYCMatchParams } from './kyc'; diff --git a/src/resources/intel/intel.ts b/src/resources/intel/intel.ts new file mode 100644 index 0000000..3160268 --- /dev/null +++ b/src/resources/intel/intel.ts @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../resource'; +import * as KYCAPI from './kyc'; +import { KYC, KYCMatchParams, KYCMatchResponse } from './kyc'; + +export class Intel extends APIResource { + kyc: KYCAPI.KYC = new KYCAPI.KYC(this._client); +} + +Intel.KYC = KYC; + +export declare namespace Intel { + export { KYC as KYC, type KYCMatchResponse as KYCMatchResponse, type KYCMatchParams as KYCMatchParams }; +} diff --git a/src/resources/intel/kyc.ts b/src/resources/intel/kyc.ts new file mode 100644 index 0000000..209d23b --- /dev/null +++ b/src/resources/intel/kyc.ts @@ -0,0 +1,190 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../resource'; +import * as Core from '../../core'; + +/** + * Retrieve detailed information about a phone number including carrier data, line type, and portability status. + */ +export class KYC extends APIResource { + /** + * Verify identity attributes against the subscriber record held by the end-user's + * mobile operator. Send a phone number along with the attributes to check; Prelude + * resolves the operator internally and returns a per-attribute match. Currently + * available for France only (Orange, SFR, Bouygues) and must be enabled for your + * account. + * + * @example + * ```ts + * const response = await client.intel.kyc.match( + * '+12065550100', + * ); + * ``` + */ + match( + phone: string, + body: KYCMatchParams, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.post(`/v2/intel/kyc/match/${phone}`, { body, ...options }); + } +} + +/** + * The per-attribute match result. Each `_match` field is one of `true`, + * `false`, or `not_available` (the operator could not answer for that attribute). + * Fuzzy attributes additionally return a `_match_score` (0-99 + * similarity) when they do not match exactly; the score is omitted on a match or + * when `not_available`. + */ +export interface KYCMatchResponse { + /** + * Whether the street address matched the operator's record. + */ + address_match?: 'true' | 'false' | 'not_available'; + + /** + * Similarity score (0-99) for the address. Returned only on a non-match. + */ + address_match_score?: number; + + /** + * Whether the date of birth matched the operator's record. Compared exactly; never + * scored. + */ + birthdate_match?: 'true' | 'false' | 'not_available'; + + /** + * The country code of the phone number. + */ + country_code?: string; + + /** + * Whether the country matched the operator's record. Compared exactly; never + * scored. + */ + country_match?: 'true' | 'false' | 'not_available'; + + /** + * Whether the email address matched the operator's record. + */ + email_match?: 'true' | 'false' | 'not_available'; + + /** + * Similarity score (0-99) for the email. Returned only on a non-match. + */ + email_match_score?: number; + + /** + * Whether the family name matched the operator's record. + */ + family_name_match?: 'true' | 'false' | 'not_available'; + + /** + * Similarity score (0-99) for the family name. Returned only on a non-match. + */ + family_name_match_score?: number; + + /** + * Whether the given name matched the operator's record. + */ + given_name_match?: 'true' | 'false' | 'not_available'; + + /** + * Similarity score (0-99) for the given name. Returned only on a non-match. + */ + given_name_match_score?: number; + + /** + * Whether the locality matched the operator's record. + */ + locality_match?: 'true' | 'false' | 'not_available'; + + /** + * Similarity score (0-99) for the locality. Returned only on a non-match. + */ + locality_match_score?: number; + + /** + * The mobile operator that answered the match. + */ + operator?: string; + + /** + * The phone number that was matched, in E.164 format. + */ + phone_number?: string; + + /** + * Whether the postal code matched the operator's record. Compared exactly; never + * scored. + */ + postal_code_match?: 'true' | 'false' | 'not_available'; + + /** + * Whether the region matched the operator's record. + */ + region_match?: 'true' | 'false' | 'not_available'; + + /** + * Similarity score (0-99) for the region. Returned only on a non-match. + */ + region_match_score?: number; + + /** + * A string that identifies this specific request. Report it back to us to help us + * diagnose your issues. + */ + request_id?: string; +} + +export interface KYCMatchParams { + /** + * The street address. + */ + address?: string; + + /** + * The date of birth in ISO 8601 (`YYYY-MM-DD`) format. Compared exactly. + */ + birthdate?: string; + + /** + * The ISO 3166-1 alpha-2 country code. Compared exactly. + */ + country?: string; + + /** + * The email address. + */ + email?: string; + + /** + * The end-user's family (last) name. + */ + family_name?: string; + + /** + * The end-user's given (first) name. + */ + given_name?: string; + + /** + * The locality (city). + */ + locality?: string; + + /** + * The postal code. Compared exactly. + */ + postal_code?: string; + + /** + * The region, state, or province. + */ + region?: string; +} + +export declare namespace KYC { + export { type KYCMatchResponse as KYCMatchResponse, type KYCMatchParams as KYCMatchParams }; +} diff --git a/src/resources/notify.ts b/src/resources/notify.ts index a538590..5979120 100644 --- a/src/resources/notify.ts +++ b/src/resources/notify.ts @@ -167,6 +167,24 @@ export class Notify extends APIResource { }); } + /** + * Send a free-form text reply to an inbound WhatsApp message within the 24-hour + * conversation window. See + * [WhatsApp 2-Way Messaging](/notify/v2/documentation/whatsapp) for details. + * + * @example + * ```ts + * const response = await client.notify.reply({ + * reply_to: 'im_01k8aq2zggeyssvt53zgvpx63a', + * text: "Thanks for reaching out! We'll look into your request.", + * to: '+33612345678', + * }); + * ``` + */ + reply(body: NotifyReplyParams, options?: Core.RequestOptions): Core.APIPromise { + return this._client.post('/v2/notify/reply', { body, ...options }); + } + /** * Send transactional and marketing messages to your users via SMS, RCS and * WhatsApp with automatic compliance enforcement. @@ -511,6 +529,43 @@ export namespace NotifyListSubscriptionPhoneNumbersResponse { } } +export interface NotifyReplyResponse { + /** + * The reply message identifier. + */ + id: string; + + /** + * The reply creation date in RFC3339 format. + */ + created_at: string; + + /** + * The inbound message ID this reply was sent in response to. + */ + reply_to: string; + + /** + * The reply message body that was sent. + */ + text: string; + + /** + * The recipient's phone number in E.164 format. + */ + to: string; + + /** + * The callback URL where webhooks will be sent. + */ + callback_url?: string; + + /** + * The user-defined correlation identifier echoed back from the request. + */ + correlation_id?: string; +} + export interface NotifySendResponse { /** * The message identifier. @@ -762,6 +817,36 @@ export interface NotifyListSubscriptionPhoneNumbersParams { state?: 'SUB' | 'UNSUB'; } +export interface NotifyReplyParams { + /** + * The inbound message ID (prefixed with `im_`) to reply to. This ID is provided in + * the `inbound.message.received` webhook event. + */ + reply_to: string; + + /** + * The reply message body sent as a free-form WhatsApp text. + */ + text: string; + + /** + * The recipient's phone number in E.164 format. Must match the phone number that + * sent the original inbound message. + */ + to: string; + + /** + * The URL where webhooks will be sent for delivery events of this reply. + */ + callback_url?: string; + + /** + * A user-defined identifier to correlate this reply with your internal systems. It + * is returned in the response and any webhook events that refer to this message. + */ + correlation_id?: string; +} + export interface NotifySendParams { /** * The template identifier configured by your Customer Success team. @@ -988,11 +1073,13 @@ export declare namespace Notify { type NotifyListSubscriptionConfigsResponse as NotifyListSubscriptionConfigsResponse, type NotifyListSubscriptionPhoneNumberEventsResponse as NotifyListSubscriptionPhoneNumberEventsResponse, type NotifyListSubscriptionPhoneNumbersResponse as NotifyListSubscriptionPhoneNumbersResponse, + type NotifyReplyResponse as NotifyReplyResponse, type NotifySendResponse as NotifySendResponse, type NotifySendBatchResponse as NotifySendBatchResponse, type NotifyListSubscriptionConfigsParams as NotifyListSubscriptionConfigsParams, type NotifyListSubscriptionPhoneNumberEventsParams as NotifyListSubscriptionPhoneNumberEventsParams, type NotifyListSubscriptionPhoneNumbersParams as NotifyListSubscriptionPhoneNumbersParams, + type NotifyReplyParams as NotifyReplyParams, type NotifySendParams as NotifySendParams, type NotifySendBatchParams as NotifySendBatchParams, }; diff --git a/src/resources/shared.ts b/src/resources/shared.ts new file mode 100644 index 0000000..4eb0bef --- /dev/null +++ b/src/resources/shared.ts @@ -0,0 +1,87 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * The signals used for anti-fraud. For more details, refer to + * [Signals](/verify/v2/documentation/prevent-fraud#signals). + */ +export interface Signals { + /** + * The version of your application. + */ + app_version?: string; + + /** + * A unique ID for the user's device. You should ensure that each user device has a + * unique `device_id` value. Ideally, for Android, this corresponds to the + * `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. + */ + device_id?: string; + + /** + * The model of the user's device. + */ + device_model?: string; + + /** + * The type of the user's device. + */ + device_platform?: 'android' | 'ios' | 'ipados' | 'tvos' | 'web'; + + /** + * Whether the end-user already exists in your system, for example an existing + * account signing in again rather than a first-time signup. Unlike + * `is_trusted_user`, this signal does not bypass fraud checks; it is taken into + * account as one additional anti-fraud signal. For more details, refer to + * [Signals](/verify/v2/documentation/prevent-fraud#signals). + */ + existing_user?: boolean; + + /** + * The public IP v4 or v6 address of the end-user's device. You should collect this + * from your backend. If your backend is behind a proxy, use the `X-Forwarded-For`, + * `Forwarded`, `True-Client-IP`, `CF-Connecting-IP` or an equivalent header to get + * the actual public IP of the end-user's device. + */ + ip?: string; + + /** + * This signal should indicate a higher level of trust, explicitly stating that the + * user is genuine. Contact us to discuss your use case. For more details, refer to + * [Signals](/verify/v2/documentation/prevent-fraud#signals). + */ + is_trusted_user?: boolean; + + /** + * The JA4 fingerprint observed for the end-user's connection. Prelude will infer + * it automatically when you use our Frontend SDKs (which use Prelude's edge + * network), but you can also forward the value if you terminate TLS yourself. + */ + ja4_fingerprint?: string; + + /** + * The version of the user's device operating system. + */ + os_version?: string; + + /** + * The user agent of the user's device. If the individual fields (os_version, + * device_platform, device_model) are provided, we will prioritize those values + * instead of parsing them from the user agent string. + */ + user_agent?: string; +} + +/** + * The operation target. Either a phone number or an email address. + */ +export interface Target { + /** + * The type of the target. Either "phone_number" or "email_address". + */ + type: 'phone_number' | 'email_address'; + + /** + * An E.164 formatted phone number or an email address. + */ + value: string; +} diff --git a/src/resources/verification-management.ts b/src/resources/verification-management.ts index fabae00..eb77d9f 100644 --- a/src/resources/verification-management.ts +++ b/src/resources/verification-management.ts @@ -1,231 +1,3 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; -import * as Core from '../core'; - -/** - * Verify phone numbers. - */ -export class VerificationManagement extends APIResource { - /** - * Remove a phone number from the allow or block list. - * - * This operation is idempotent - re-deleting the same phone number will not result - * in errors. If the phone number does not exist in the specified list, the - * operation will succeed without making any changes. - * - * In order to get access to this endpoint, contact our support team. - * - * @example - * ```ts - * const response = - * await client.verificationManagement.deletePhoneNumber( - * 'allow', - * { phone_number: '+30123456789' }, - * ); - * ``` - */ - deletePhoneNumber( - action: 'allow' | 'block', - body: VerificationManagementDeletePhoneNumberParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.delete(`/v2/verification/management/phone-numbers/${action}`, { body, ...options }); - } - - /** - * Retrieve the list of phone numbers in the allow or block list. - * - * In order to get access to this endpoint, contact our support team. - * - * @example - * ```ts - * const response = - * await client.verificationManagement.listPhoneNumbers( - * 'allow', - * ); - * ``` - */ - listPhoneNumbers( - action: 'allow' | 'block', - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.get(`/v2/verification/management/phone-numbers/${action}`, options); - } - - /** - * Retrieve sender IDs list. - * - * In order to get access to this endpoint, contact our support team. - * - * @example - * ```ts - * const response = - * await client.verificationManagement.listSenderIds(); - * ``` - */ - listSenderIds(options?: Core.RequestOptions): Core.APIPromise { - return this._client.get('/v2/verification/management/sender-id', options); - } - - /** - * Add a phone number to the allow or block list. - * - * This operation is idempotent - re-adding the same phone number will not result - * in duplicate entries or errors. If the phone number already exists in the - * specified list, the operation will succeed without making any changes. - * - * In order to get access to this endpoint, contact our support team. - * - * @example - * ```ts - * const response = - * await client.verificationManagement.setPhoneNumber( - * 'allow', - * { phone_number: '+30123456789' }, - * ); - * ``` - */ - setPhoneNumber( - action: 'allow' | 'block', - body: VerificationManagementSetPhoneNumberParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/v2/verification/management/phone-numbers/${action}`, { body, ...options }); - } - - /** - * This endpoint allows you to submit a new sender ID for verification purposes. - * - * In order to get access to this endpoint, contact our support team. - * - * @example - * ```ts - * const response = - * await client.verificationManagement.submitSenderId({ - * sender_id: 'Prelude', - * }); - * ``` - */ - submitSenderId( - body: VerificationManagementSubmitSenderIDParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post('/v2/verification/management/sender-id', { body, ...options }); - } -} - -export interface VerificationManagementDeletePhoneNumberResponse { - /** - * The E.164 formatted phone number that was removed from the list. - */ - phone_number: string; -} - -export interface VerificationManagementListPhoneNumbersResponse { - /** - * A list of phone numbers in the allow or block list. - */ - phone_numbers: Array; -} - -export namespace VerificationManagementListPhoneNumbersResponse { - export interface PhoneNumber { - /** - * The date and time when the phone number was added to the list. - */ - created_at: string; - - /** - * An E.164 formatted phone number. - */ - phone_number: string; - } -} - -/** - * A list of Sender ID. - */ -export interface VerificationManagementListSenderIDsResponse { - sender_ids?: Array; -} - -export namespace VerificationManagementListSenderIDsResponse { - export interface SenderID { - /** - * Value that will be presented as Sender ID - */ - sender_id?: string; - - /** - * It indicates the status of the Sender ID. Possible values are: - * - * - `approved` - The Sender ID is approved. - * - `pending` - The Sender ID is pending. - * - `rejected` - The Sender ID is rejected. - */ - status?: 'approved' | 'pending' | 'rejected'; - } -} - -export interface VerificationManagementSetPhoneNumberResponse { - /** - * The E.164 formatted phone number that was added to the list. - */ - phone_number: string; -} - -export interface VerificationManagementSubmitSenderIDResponse { - /** - * The sender ID that was added. - */ - sender_id: string; - - /** - * It indicates the status of the sender ID. Possible values are: - * - * - `approved` - The sender ID is approved. - * - `pending` - The sender ID is pending. - * - `rejected` - The sender ID is rejected. - */ - status: 'approved' | 'pending' | 'rejected'; - - /** - * The reason why the sender ID was rejected. - */ - reason?: string; -} - -export interface VerificationManagementDeletePhoneNumberParams { - /** - * An E.164 formatted phone number to remove from the list. - */ - phone_number: string; -} - -export interface VerificationManagementSetPhoneNumberParams { - /** - * An E.164 formatted phone number to add to the list. - */ - phone_number: string; -} - -export interface VerificationManagementSubmitSenderIDParams { - /** - * The sender ID to add. - */ - sender_id: string; -} - -export declare namespace VerificationManagement { - export { - type VerificationManagementDeletePhoneNumberResponse as VerificationManagementDeletePhoneNumberResponse, - type VerificationManagementListPhoneNumbersResponse as VerificationManagementListPhoneNumbersResponse, - type VerificationManagementListSenderIDsResponse as VerificationManagementListSenderIDsResponse, - type VerificationManagementSetPhoneNumberResponse as VerificationManagementSetPhoneNumberResponse, - type VerificationManagementSubmitSenderIDResponse as VerificationManagementSubmitSenderIDResponse, - type VerificationManagementDeletePhoneNumberParams as VerificationManagementDeletePhoneNumberParams, - type VerificationManagementSetPhoneNumberParams as VerificationManagementSetPhoneNumberParams, - type VerificationManagementSubmitSenderIDParams as VerificationManagementSubmitSenderIDParams, - }; -} +export * from './verification-management/index'; diff --git a/src/resources/verification-management/index.ts b/src/resources/verification-management/index.ts new file mode 100644 index 0000000..37b8604 --- /dev/null +++ b/src/resources/verification-management/index.ts @@ -0,0 +1,20 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Sandbox, + type SandboxAddPhoneNumberResponse, + type SandboxDeletePhoneNumberResponse, + type SandboxListPhoneNumbersResponse, + type SandboxAddPhoneNumberParams, +} from './sandbox'; +export { + VerificationManagement, + type VerificationManagementDeletePhoneNumberResponse, + type VerificationManagementListPhoneNumbersResponse, + type VerificationManagementListSenderIDsResponse, + type VerificationManagementSetPhoneNumberResponse, + type VerificationManagementSubmitSenderIDResponse, + type VerificationManagementDeletePhoneNumberParams, + type VerificationManagementSetPhoneNumberParams, + type VerificationManagementSubmitSenderIDParams, +} from './verification-management'; diff --git a/src/resources/verification-management/sandbox.ts b/src/resources/verification-management/sandbox.ts new file mode 100644 index 0000000..f3f47f7 --- /dev/null +++ b/src/resources/verification-management/sandbox.ts @@ -0,0 +1,144 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../resource'; +import * as Core from '../../core'; + +/** + * Verify phone numbers. + */ +export class Sandbox extends APIResource { + /** + * Register a phone number as a sandbox number and associate it with a fixed + * attempt code. Subsequent verification attempts against this number will not + * trigger a real SMS/call and will validate against the configured attempt code. + * + * This operation is idempotent - re-adding the same phone number will overwrite + * the existing attempt code. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.sandbox.addPhoneNumber( + * { + * attempt_code: '123456', + * phone_number: '+30123456789', + * }, + * ); + * ``` + */ + addPhoneNumber( + body: SandboxAddPhoneNumberParams, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.put('/v2/verification/management/phone-numbers/sandbox', { body, ...options }); + } + + /** + * Remove a phone number from the sandbox list. + * + * This operation is idempotent - deleting a phone number that is not in the + * sandbox list will succeed without making any changes. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.sandbox.deletePhoneNumber( + * '+12065550100', + * ); + * ``` + */ + deletePhoneNumber( + phoneNumber: string, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.delete(`/v2/verification/management/phone-numbers/sandbox/${phoneNumber}`, options); + } + + /** + * Retrieve the list of sandbox phone numbers for the account. Sandbox numbers are + * test numbers that bypass the real verification flow and return a fixed attempt + * code. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.sandbox.listPhoneNumbers(); + * ``` + */ + listPhoneNumbers(options?: Core.RequestOptions): Core.APIPromise { + return this._client.get('/v2/verification/management/phone-numbers/sandbox', options); + } +} + +export interface SandboxAddPhoneNumberResponse { + /** + * The fixed attempt code associated with the sandbox phone number. + */ + attempt_code: string; + + /** + * The E.164 formatted phone number that was added to the sandbox list. + */ + phone_number: string; +} + +export interface SandboxDeletePhoneNumberResponse { + /** + * The E.164 formatted phone number that was removed from the sandbox list. + */ + phone_number: string; +} + +export interface SandboxListPhoneNumbersResponse { + /** + * A list of sandbox phone numbers. + */ + phone_numbers: Array; +} + +export namespace SandboxListPhoneNumbersResponse { + export interface PhoneNumber { + /** + * The fixed attempt code associated with the sandbox phone number. + */ + attempt_code: string; + + /** + * The date and time when the phone number was added to the sandbox list. + */ + created_at: string; + + /** + * An E.164 formatted phone number. + */ + phone_number: string; + } +} + +export interface SandboxAddPhoneNumberParams { + /** + * The fixed attempt code that will validate verification attempts for this phone + * number. + */ + attempt_code: string; + + /** + * An E.164 formatted phone number to add to the sandbox list. + */ + phone_number: string; +} + +export declare namespace Sandbox { + export { + type SandboxAddPhoneNumberResponse as SandboxAddPhoneNumberResponse, + type SandboxDeletePhoneNumberResponse as SandboxDeletePhoneNumberResponse, + type SandboxListPhoneNumbersResponse as SandboxListPhoneNumbersResponse, + type SandboxAddPhoneNumberParams as SandboxAddPhoneNumberParams, + }; +} diff --git a/src/resources/verification-management/verification-management.ts b/src/resources/verification-management/verification-management.ts new file mode 100644 index 0000000..f005d18 --- /dev/null +++ b/src/resources/verification-management/verification-management.ts @@ -0,0 +1,251 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../resource'; +import * as Core from '../../core'; +import * as SandboxAPI from './sandbox'; +import { + Sandbox, + SandboxAddPhoneNumberParams, + SandboxAddPhoneNumberResponse, + SandboxDeletePhoneNumberResponse, + SandboxListPhoneNumbersResponse, +} from './sandbox'; + +/** + * Verify phone numbers. + */ +export class VerificationManagement extends APIResource { + sandbox: SandboxAPI.Sandbox = new SandboxAPI.Sandbox(this._client); + + /** + * Remove a phone number from the allow or block list. + * + * This operation is idempotent - re-deleting the same phone number will not result + * in errors. If the phone number does not exist in the specified list, the + * operation will succeed without making any changes. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.deletePhoneNumber( + * 'allow', + * { phone_number: '+30123456789' }, + * ); + * ``` + */ + deletePhoneNumber( + action: 'allow' | 'block', + body: VerificationManagementDeletePhoneNumberParams, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.delete(`/v2/verification/management/phone-numbers/${action}`, { body, ...options }); + } + + /** + * Retrieve the list of phone numbers in the allow or block list. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.listPhoneNumbers( + * 'allow', + * ); + * ``` + */ + listPhoneNumbers( + action: 'allow' | 'block', + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.get(`/v2/verification/management/phone-numbers/${action}`, options); + } + + /** + * Retrieve sender IDs list. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.listSenderIds(); + * ``` + */ + listSenderIds(options?: Core.RequestOptions): Core.APIPromise { + return this._client.get('/v2/verification/management/sender-id', options); + } + + /** + * Add a phone number to the allow or block list. + * + * This operation is idempotent - re-adding the same phone number will not result + * in duplicate entries or errors. If the phone number already exists in the + * specified list, the operation will succeed without making any changes. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.setPhoneNumber( + * 'allow', + * { phone_number: '+30123456789' }, + * ); + * ``` + */ + setPhoneNumber( + action: 'allow' | 'block', + body: VerificationManagementSetPhoneNumberParams, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.post(`/v2/verification/management/phone-numbers/${action}`, { body, ...options }); + } + + /** + * This endpoint allows you to submit a new sender ID for verification purposes. + * + * In order to get access to this endpoint, contact our support team. + * + * @example + * ```ts + * const response = + * await client.verificationManagement.submitSenderId({ + * sender_id: 'Prelude', + * }); + * ``` + */ + submitSenderId( + body: VerificationManagementSubmitSenderIDParams, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.post('/v2/verification/management/sender-id', { body, ...options }); + } +} + +export interface VerificationManagementDeletePhoneNumberResponse { + /** + * The E.164 formatted phone number that was removed from the list. + */ + phone_number: string; +} + +export interface VerificationManagementListPhoneNumbersResponse { + /** + * A list of phone numbers in the allow or block list. + */ + phone_numbers: Array; +} + +export namespace VerificationManagementListPhoneNumbersResponse { + export interface PhoneNumber { + /** + * The date and time when the phone number was added to the list. + */ + created_at: string; + + /** + * An E.164 formatted phone number. + */ + phone_number: string; + } +} + +/** + * A list of Sender ID. + */ +export interface VerificationManagementListSenderIDsResponse { + sender_ids?: Array; +} + +export namespace VerificationManagementListSenderIDsResponse { + export interface SenderID { + /** + * Value that will be presented as Sender ID + */ + sender_id?: string; + + /** + * It indicates the status of the Sender ID. Possible values are: + * + * - `approved` - The Sender ID is approved. + * - `pending` - The Sender ID is pending. + * - `rejected` - The Sender ID is rejected. + */ + status?: 'approved' | 'pending' | 'rejected'; + } +} + +export interface VerificationManagementSetPhoneNumberResponse { + /** + * The E.164 formatted phone number that was added to the list. + */ + phone_number: string; +} + +export interface VerificationManagementSubmitSenderIDResponse { + /** + * The sender ID that was added. + */ + sender_id: string; + + /** + * It indicates the status of the sender ID. Possible values are: + * + * - `approved` - The sender ID is approved. + * - `pending` - The sender ID is pending. + * - `rejected` - The sender ID is rejected. + */ + status: 'approved' | 'pending' | 'rejected'; + + /** + * The reason why the sender ID was rejected. + */ + reason?: string; +} + +export interface VerificationManagementDeletePhoneNumberParams { + /** + * An E.164 formatted phone number to remove from the list. + */ + phone_number: string; +} + +export interface VerificationManagementSetPhoneNumberParams { + /** + * An E.164 formatted phone number to add to the list. + */ + phone_number: string; +} + +export interface VerificationManagementSubmitSenderIDParams { + /** + * The sender ID to add. + */ + sender_id: string; +} + +VerificationManagement.Sandbox = Sandbox; + +export declare namespace VerificationManagement { + export { + type VerificationManagementDeletePhoneNumberResponse as VerificationManagementDeletePhoneNumberResponse, + type VerificationManagementListPhoneNumbersResponse as VerificationManagementListPhoneNumbersResponse, + type VerificationManagementListSenderIDsResponse as VerificationManagementListSenderIDsResponse, + type VerificationManagementSetPhoneNumberResponse as VerificationManagementSetPhoneNumberResponse, + type VerificationManagementSubmitSenderIDResponse as VerificationManagementSubmitSenderIDResponse, + type VerificationManagementDeletePhoneNumberParams as VerificationManagementDeletePhoneNumberParams, + type VerificationManagementSetPhoneNumberParams as VerificationManagementSetPhoneNumberParams, + type VerificationManagementSubmitSenderIDParams as VerificationManagementSubmitSenderIDParams, + }; + + export { + Sandbox as Sandbox, + type SandboxAddPhoneNumberResponse as SandboxAddPhoneNumberResponse, + type SandboxDeletePhoneNumberResponse as SandboxDeletePhoneNumberResponse, + type SandboxListPhoneNumbersResponse as SandboxListPhoneNumbersResponse, + type SandboxAddPhoneNumberParams as SandboxAddPhoneNumberParams, + }; +} diff --git a/src/resources/verification.ts b/src/resources/verification.ts index 5ab1656..d46fce2 100644 --- a/src/resources/verification.ts +++ b/src/resources/verification.ts @@ -1,559 +1,3 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; -import * as Core from '../core'; - -/** - * Verify phone numbers. - */ -export class Verification extends APIResource { - /** - * Create a new verification for a specific phone number. If another non-expired - * verification exists (the request is performed within the verification window), - * this endpoint will perform a retry instead. - * - * @example - * ```ts - * const verification = await client.verification.create({ - * target: { type: 'phone_number', value: '+30123456789' }, - * }); - * ``` - */ - create( - body: VerificationCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post('/v2/verification', { body, ...options }); - } - - /** - * Check the validity of a verification code. - * - * @example - * ```ts - * const response = await client.verification.check({ - * code: '12345', - * target: { type: 'phone_number', value: '+30123456789' }, - * }); - * ``` - */ - check( - body: VerificationCheckParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post('/v2/verification/check', { body, ...options }); - } -} - -export interface VerificationCreateResponse { - /** - * The verification identifier. - */ - id: string; - - /** - * The method used for verifying this phone number. - */ - method: 'email' | 'message' | 'silent' | 'voice'; - - /** - * The status of the verification. - * - * - `success` - A new verification window was created. - * - `retry` - A new attempt was created for an existing verification window. - * - `challenged` - The verification is suspicious and is restricted to non-SMS and - * non-voice channels only. This mode must be enabled for your customer account - * by Prelude support. - * - `blocked` - The verification was blocked. - * - `shadow_blocked` - The verification triggered a block rule but the decision - * was not enforced; this is used to dry-run anti-fraud configuration. This mode - * must be enabled for your customer account by Prelude support. - */ - status: 'success' | 'retry' | 'challenged' | 'blocked' | 'shadow_blocked'; - - /** - * The ordered sequence of channels to be used for verification - */ - channels?: Array<'rcs' | 'silent' | 'sms' | 'telegram' | 'viber' | 'voice' | 'whatsapp' | 'zalo'>; - - /** - * The metadata for this verification. - */ - metadata?: VerificationCreateResponse.Metadata; - - /** - * The reason why the verification was blocked. Only present when status is - * "blocked" or "shadow_blocked". - * - * - `expired_signature` - The signature of the SDK signals is expired. They should - * be sent within the hour following their collection. - * - `in_block_list` - The phone number is part of the configured block list. - * - `invalid_phone_line` - The phone number is not a valid line number (e.g. - * landline). - * - `invalid_phone_number` - The phone number is not a valid phone number (e.g. - * unallocated range). - * - `invalid_signature` - The signature of the SDK signals is invalid. - * - `repeated_attempts` - The phone number has made too many verification - * attempts. - * - `suspicious` - The verification attempt was deemed suspicious by the - * anti-fraud system. - */ - reason?: - | 'expired_signature' - | 'in_block_list' - | 'invalid_phone_line' - | 'invalid_phone_number' - | 'invalid_signature' - | 'repeated_attempts' - | 'suspicious'; - - request_id?: string; - - /** - * The risk factors that contributed to the verification being blocked. Only - * present when status is "blocked" or "shadow_blocked" and the anti-fraud system - * detected specific risk signals. - * - * - `behavioral_pattern` - The phone number past behavior during verification - * flows exhibits suspicious patterns. - * - `device_attribute` - The device exhibits characteristics associated with - * suspicious activity patterns. - * - `fraud_database` - The phone number has been flagged as suspicious in one or - * more of our fraud databases. - * - `location_discrepancy` - The phone number prefix and IP address discrepancy - * indicates potential fraud. - * - `network_fingerprint` - The network connection exhibits characteristics - * associated with suspicious activity patterns. - * - `poor_conversion_history` - The phone number has a history of poorly - * converting to a verified phone number. - * - `prefix_concentration` - The phone number is part of a range known to be - * associated with suspicious activity patterns. - * - `suspected_request_tampering` - The SDK signature is invalid and the request - * is considered to be tampered with. - * - `suspicious_ip_address` - The IP address is deemed to be associated with - * suspicious activity patterns. - * - `temporary_phone_number` - The phone number is known to be a temporary or - * disposable number. - */ - risk_factors?: Array< - | 'behavioral_pattern' - | 'device_attribute' - | 'fraud_database' - | 'location_discrepancy' - | 'network_fingerprint' - | 'poor_conversion_history' - | 'prefix_concentration' - | 'suspected_request_tampering' - | 'suspicious_ip_address' - | 'temporary_phone_number' - >; - - /** - * The silent verification specific properties. - */ - silent?: VerificationCreateResponse.Silent; -} - -export namespace VerificationCreateResponse { - /** - * The metadata for this verification. - */ - export interface Metadata { - /** - * A user-defined identifier to correlate this verification with. It is returned in - * the response and any webhook events that refer to this verification. - */ - correlation_id?: string; - } - - /** - * The silent verification specific properties. - */ - export interface Silent { - /** - * The URL to start the silent verification towards. - */ - request_url: string; - } -} - -export interface VerificationCheckResponse { - /** - * The status of the check. For `prelude:psd2` codes, `transaction_missing` is - * returned when the `psd2` block is omitted, and `transaction_mismatch` when the - * submitted variables differ from those provided at issuance. - */ - status: 'success' | 'failure' | 'expired_or_not_found' | 'transaction_missing' | 'transaction_mismatch'; - - /** - * The verification identifier. - */ - id?: string; - - /** - * The metadata for this verification. - */ - metadata?: VerificationCheckResponse.Metadata; - - request_id?: string; -} - -export namespace VerificationCheckResponse { - /** - * The metadata for this verification. - */ - export interface Metadata { - /** - * A user-defined identifier to correlate this verification with. It is returned in - * the response and any webhook events that refer to this verification. - */ - correlation_id?: string; - } -} - -export interface VerificationCreateParams { - /** - * The verification target. Either a phone number or an email address. To use the - * email verification feature contact us to discuss your use case. - */ - target: VerificationCreateParams.Target; - - /** - * The identifier of the dispatch that came from the front-end SDK. - */ - dispatch_id?: string; - - /** - * The metadata for this verification. This object will be returned with every - * response or webhook sent that refers to this verification. - */ - metadata?: VerificationCreateParams.Metadata; - - /** - * Verification options - */ - options?: VerificationCreateParams.Options; - - /** - * The signals used for anti-fraud. For more details, refer to - * [Signals](/verify/v2/documentation/prevent-fraud#signals). - */ - signals?: VerificationCreateParams.Signals; -} - -export namespace VerificationCreateParams { - /** - * The verification target. Either a phone number or an email address. To use the - * email verification feature contact us to discuss your use case. - */ - export interface Target { - /** - * The type of the target. Either "phone_number" or "email_address". - */ - type: 'phone_number' | 'email_address'; - - /** - * An E.164 formatted phone number or an email address. - */ - value: string; - } - - /** - * The metadata for this verification. This object will be returned with every - * response or webhook sent that refers to this verification. - */ - export interface Metadata { - /** - * A user-defined identifier to correlate this verification with. It is returned in - * the response and any webhook events that refer to this verification. - */ - correlation_id?: string; - } - - /** - * Verification options - */ - export interface Options { - /** - * This allows automatic OTP retrieval on mobile apps and web browsers. Supported - * platforms are Android (SMS Retriever API) and Web (WebOTP API). - */ - app_realm?: Options.AppRealm; - - /** - * The URL where webhooks will be sent when verification events occur, including - * verification creation, attempt creation, and delivery status changes. For more - * details, refer to [Webhook](/verify/v2/documentation/webhook). - */ - callback_url?: string; - - /** - * The channels this verification may use, in the order they are tried. Channels - * you omit are never used, including on retries. This option can only be set when - * the verification is created. The list is recorded on the verification and - * applies for its whole lifecycle, so `channels` sent while retrying an existing - * verification is ignored — unlike `preferred_channel`, which is honored on every - * retry. Every channel you list must be enabled on your account and active in the - * destination country, otherwise the request fails with - * `channel_not_enabled_in_region`. Prelude still picks the best provider within - * each channel. Cannot be combined with `preferred_channel`. Voice is requested - * through `method` instead. Disabled by default — contact support to enable it. - */ - channels?: Array<'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram'>; - - /** - * The size of the code generated. It should be between 4 and 8. Defaults to the - * code size specified from the Dashboard. - */ - code_size?: number; - - /** - * The custom code to use for OTP verification. To use the custom code feature, - * contact us to enable it for your account. For more details, refer to - * [Custom Code](/verify/v2/documentation/custom-codes). - */ - custom_code?: string; - - /** - * When `true`, the verification is routed through challenge-safe channels - * (non-SMS/Voice) regardless of country eligibility or any antispam outcome. The - * resulting verification has `status: "challenged"`. Use this when you have your - * own signal that the request is suspicious and want stricter routing — the - * verification is **not** classified as fraud and does not contribute to - * anti-fraud counters or risk factors. This feature is disabled by default — - * contact Prelude support to enable it on your account. - */ - force_challenge?: boolean; - - /** - * A BCP-47 formatted locale string with the language the text message will be sent - * to. If there's no locale set, the language will be determined by the country - * code of the phone number. If the language specified doesn't exist, it defaults - * to US English. - */ - locale?: string; - - /** - * Maximum number of delivery attempts Prelude may add on its own after the one you - * requested. `0` means a single attempt: if it cannot be delivered, Prelude - * neither tries another provider nor another channel, and does not retry - * automatically. `1` allows one additional attempt, and so on — a value larger - * than the number of routes available for the destination simply behaves like the - * default. When omitted, Prelude retries as your account is configured, across as - * many channels as the route offers. - * - * This option can only be set when the verification is created. The value is - * recorded on the verification and applies for its whole lifecycle, so a - * `max_auto_fallbacks` sent while retrying an existing verification is ignored — - * the limit cannot be raised or lowered after the fact. A retry you ask for is not - * an automatic attempt, so it gets a fresh allowance of the same limit. This - * option is disabled by default — contact Prelude support to enable it on your - * account. - */ - max_auto_fallbacks?: number; - - /** - * The method used for verifying this phone number. The 'voice' option provides an - * accessible alternative for visually impaired users by delivering the - * verification code through a phone call rather than a text message. It also - * allows verification of landline numbers that cannot receive SMS messages. The - * 'message' option explicitly requests message delivery (SMS, WhatsApp ...) and - * skips silent verification, useful for scenarios requiring direct user - * interaction. - */ - method?: 'auto' | 'voice' | 'message'; - - /** - * The channel to prioritize when delivering the verification. Prelude prioritizes - * this channel on the first attempt and continues to prefer it on retries while an - * untried route on that channel remains; once those are exhausted, retries fall - * back to the next best available route. If the channel is unavailable (for - * example, when a verification is challenged), Prelude uses the best available - * route instead. Cannot be combined with `channels`. - */ - preferred_channel?: 'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram'; - - /** - * The Sender ID to use for this message. The Sender ID needs to be enabled by - * Prelude. - */ - sender_id?: string; - - /** - * The identifier of a verification template. It applies use case-specific - * settings, such as the message content or certain verification parameters. - */ - template_id?: string; - - /** - * The variables to be replaced in the template. - */ - variables?: { [key: string]: string }; - } - - export namespace Options { - /** - * This allows automatic OTP retrieval on mobile apps and web browsers. Supported - * platforms are Android (SMS Retriever API) and Web (WebOTP API). - */ - export interface AppRealm { - /** - * The platform for automatic OTP retrieval. Use "android" for the SMS Retriever - * API or "web" for the WebOTP API. - */ - platform: 'android' | 'web'; - - /** - * The value depends on the platform: - * - * - For Android: The SMS Retriever API hash code (11 characters). See - * [Google documentation](https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string). - * - For Web: The origin domain (e.g., "example.com" or "www.example.com"). See - * [WebOTP API documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API). - */ - value: string; - } - } - - /** - * The signals used for anti-fraud. For more details, refer to - * [Signals](/verify/v2/documentation/prevent-fraud#signals). - */ - export interface Signals { - /** - * The version of your application. - */ - app_version?: string; - - /** - * A unique ID for the user's device. You should ensure that each user device has a - * unique `device_id` value. Ideally, for Android, this corresponds to the - * `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. - */ - device_id?: string; - - /** - * The model of the user's device. - */ - device_model?: string; - - /** - * The type of the user's device. - */ - device_platform?: 'android' | 'ios' | 'ipados' | 'tvos' | 'web'; - - /** - * Whether the end-user already exists in your system, for example an existing - * account signing in again rather than a first-time signup. Unlike - * `is_trusted_user`, this signal does not bypass fraud checks; it is taken into - * account as one additional anti-fraud signal. For more details, refer to - * [Signals](/verify/v2/documentation/prevent-fraud#signals). - */ - existing_user?: boolean; - - /** - * The public IP v4 or v6 address of the end-user's device. You should collect this - * from your backend. If your backend is behind a proxy, use the `X-Forwarded-For`, - * `Forwarded`, `True-Client-IP`, `CF-Connecting-IP` or an equivalent header to get - * the actual public IP of the end-user's device. - */ - ip?: string; - - /** - * This signal should indicate a higher level of trust, explicitly stating that the - * user is genuine. Contact us to discuss your use case. For more details, refer to - * [Signals](/verify/v2/documentation/prevent-fraud#signals). - */ - is_trusted_user?: boolean; - - /** - * The JA4 fingerprint observed for the end-user's connection. Prelude will infer - * it automatically when you use our Frontend SDKs (which use Prelude's edge - * network), but you can also forward the value if you terminate TLS yourself. - */ - ja4_fingerprint?: string; - - /** - * The version of the user's device operating system. - */ - os_version?: string; - - /** - * The user agent of the user's device. If the individual fields (os_version, - * device_platform, device_model) are provided, we will prioritize those values - * instead of parsing them from the user agent string. - */ - user_agent?: string; - } -} - -export interface VerificationCheckParams { - /** - * The OTP code to validate. - */ - code: string; - - /** - * The verification target. Either a phone number or an email address. To use the - * email verification feature contact us to discuss your use case. - */ - target: VerificationCheckParams.Target; - - /** - * Required when checking a code issued under the `prelude:psd2` template. The - * submitted variables must match those provided at issuance; any mismatch - * invalidates the code (PSD2 SCA RTS Article 5 dynamic linking). Ignored on - * non-PSD2 verifications. - */ - psd2?: VerificationCheckParams.Psd2; -} - -export namespace VerificationCheckParams { - /** - * The verification target. Either a phone number or an email address. To use the - * email verification feature contact us to discuss your use case. - */ - export interface Target { - /** - * The type of the target. Either "phone_number" or "email_address". - */ - type: 'phone_number' | 'email_address'; - - /** - * An E.164 formatted phone number or an email address. - */ - value: string; - } - - /** - * Required when checking a code issued under the `prelude:psd2` template. The - * submitted variables must match those provided at issuance; any mismatch - * invalidates the code (PSD2 SCA RTS Article 5 dynamic linking). Ignored on - * non-PSD2 verifications. - */ - export interface Psd2 { - /** - * Decimal amount of the transaction. - */ - amount: string; - - /** - * ISO 4217 currency code. - */ - currency: string; - - /** - * Payee name displayed to the payer. - */ - recipient: string; - } -} - -export declare namespace Verification { - export { - type VerificationCreateResponse as VerificationCreateResponse, - type VerificationCheckResponse as VerificationCheckResponse, - type VerificationCreateParams as VerificationCreateParams, - type VerificationCheckParams as VerificationCheckParams, - }; -} +export * from './verification/index'; diff --git a/src/resources/verification/index.ts b/src/resources/verification/index.ts new file mode 100644 index 0000000..46ed84d --- /dev/null +++ b/src/resources/verification/index.ts @@ -0,0 +1,10 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Phone } from './phone/index'; +export { + Verification, + type VerificationCreateResponse, + type VerificationCheckResponse, + type VerificationCreateParams, + type VerificationCheckParams, +} from './verification'; diff --git a/src/resources/verification/phone.ts b/src/resources/verification/phone.ts new file mode 100644 index 0000000..a53cf49 --- /dev/null +++ b/src/resources/verification/phone.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './phone/index'; diff --git a/src/resources/verification/phone/history.ts b/src/resources/verification/phone/history.ts new file mode 100644 index 0000000..7bab12d --- /dev/null +++ b/src/resources/verification/phone/history.ts @@ -0,0 +1,681 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../resource'; +import { isRequestOptions } from '../../../core'; +import * as Core from '../../../core'; +import * as HistoryAPI from './history'; + +/** + * Verify phone numbers. + */ +export class History extends APIResource { + /** + * Retrieve everything Prelude recorded for one phone verification: its outcome and + * the device, network and anti-fraud context it was created in, the chronological + * timeline of every message attempt and code check, and the anti-fraud signals you + * forwarded. + * + * The identifier is the `id` returned by + * [Create or retry a verification](/verify/v2/api-reference/create-or-retry-a-verification) + * or the `verification_id` of the verification webhooks. Both `lifecycle` and + * `signals` are optional: a verification can resolve with its top-level fields + * alone. + * + * @example + * ```ts + * const history = + * await client.verification.phone.history.retrieve( + * 'vrf_01jc0t6fwwfgfsq1md24mhyztj', + * ); + * ``` + */ + retrieve(id: string, options?: Core.RequestOptions): Core.APIPromise { + return this._client.get(`/v2/verification/phone/history/${id}`, options); + } + + /** + * List your phone verifications, most recent first, one entry per verification + * with its outcome, channels, attempts and cost. Every filter is optional and they + * combine with AND. + * + * Use it to find every verification a phone number went through from your support + * tooling, then + * [Get a phone verification](/verify/v2/api-reference/history/get-a-phone-verification) + * for the full timeline of one of them. A cursor is bound to the filters that + * produced it: pass `next_cursor` back with the exact same query parameters. + * + * @example + * ```ts + * const histories = + * await client.verification.phone.history.list(); + * ``` + */ + list(query?: HistoryListParams, options?: Core.RequestOptions): Core.APIPromise; + list(options?: Core.RequestOptions): Core.APIPromise; + list( + query: HistoryListParams | Core.RequestOptions = {}, + options?: Core.RequestOptions, + ): Core.APIPromise { + if (isRequestOptions(query)) { + return this.list({}, query); + } + return this._client.get('/v2/verification/phone/history', { query, ...options }); + } +} + +/** + * The end user's mobile network. + */ +export interface PhoneVerificationCarrier { + mccmnc: string; + + name?: string; +} + +export interface PhoneVerificationMoney { + /** + * Exact decimal amount. It is never rounded to the currency's minor units, so a + * sub-cent cost reads as `0.0004` rather than as `0.00`. + */ + amount: string; + + /** + * ISO 4217 currency code. + */ + currency: string; +} + +export interface PhoneVerificationPsd2Transaction { + amount?: PhoneVerificationMoney; + + /** + * Payee name displayed to the payer. + */ + recipient?: string; +} + +/** + * A verification and everything Prelude recorded about it. + */ +export interface HistoryRetrieveResponse { + /** + * The verification identifier. + */ + id: string; + + created_at: string; + + expires_at: string; + + /** + * The E.164 phone number the verification targeted. + */ + phone_number: string; + + /** + * The outcome of the verification. + * + * - `converted` - The end user submitted a valid code. + * - `not_converted` - The verification expired without a valid code. + * - `pending_check` - A code was delivered and Prelude is still waiting for a + * check. + * - `sent` - A code was sent and the verification window is still open. + * - `challenged` - The verification was restricted to non-SMS and non-voice + * channels. + * - `suspected_fraud` - The anti-fraud system blocked the verification. + * - `in_blocklist` - The phone number is on the configured block list. + * - `invalid_line` - The phone number is not a valid line type. + * - `invalid_number` - The phone number is not a valid number. + * - `rate_limited` - The verification was refused by a rate limit. + * - `expired_signals` - The SDK signals were collected too long before the + * request. + * - `shadowed` - The anti-fraud system flagged the verification without blocking + * it. + */ + status: + | 'converted' + | 'not_converted' + | 'pending_check' + | 'sent' + | 'challenged' + | 'suspected_fraud' + | 'in_blocklist' + | 'invalid_line' + | 'invalid_number' + | 'rate_limited' + | 'expired_signals' + | 'shadowed'; + + /** + * Version of your application, when known. + */ + app_version?: string; + + /** + * Why the anti-fraud system blocked the verification. Empty unless it did. + * + * - `behavioral_pattern` - The phone number past behavior during verification + * flows exhibits suspicious patterns. + * - `device_attribute` - The end-user device reported attributes associated with + * fraud or emulation. + * - `fraud_database` - The phone number appears in a fraud database. + * - `location_discrepancy` - The phone number region and the observed location + * disagree. + * - `missing_signals` - The verification expected Prelude SDK signals and none + * arrived. + * - `network_fingerprint` - The network fingerprint matches known fraudulent + * traffic. + * - `poor_conversion_history` - The phone number rarely completes the + * verifications it starts. + * - `prefix_concentration` - The phone number is part of a range known to be + * associated with suspicious activity patterns. + * - `repeated_number` - The phone number was used far more often than normal + * traffic would explain. + * - `suspected_request_tampering` - The SDK signals were altered or expired + * between collection and use. + * - `suspicious_ip_address` - The originating IP address is associated with + * suspicious activity. + * - `temporary_phone_number` - The phone number is known to be a temporary or + * disposable number. + */ + block_reasons?: Array< + | 'behavioral_pattern' + | 'device_attribute' + | 'fraud_database' + | 'location_discrepancy' + | 'missing_signals' + | 'network_fingerprint' + | 'poor_conversion_history' + | 'prefix_concentration' + | 'repeated_number' + | 'suspected_request_tampering' + | 'suspicious_ip_address' + | 'temporary_phone_number' + >; + + /** + * The end user's mobile network. + */ + carrier?: PhoneVerificationCarrier; + + /** + * The correlation identifier you supplied when creating the verification. + */ + correlation_id?: string; + + /** + * Model of the end-user device, when known. + */ + device_model?: string; + + /** + * Platform of the end-user device, when known. + */ + device_platform?: 'android' | 'ios' | 'ipados' | 'tvos' | 'web'; + + /** + * IP address the verification was created from. + */ + ip_address?: string; + + /** + * ISO 3166-1 alpha-2 region of the caller's IP address. + */ + ip_address_region?: string; + + /** + * Distance between the phone number region and the IP location. + */ + ip_distance_meters?: number; + + /** + * Chronological timeline of the verification: creation, message attempts with + * delivery events, code checks and signals reception. Omitted when Prelude holds + * no timeline for the verification. + */ + lifecycle?: HistoryRetrieveResponse.Lifecycle; + + /** + * Whether the phone number was allow-listed, block-listed, or sandboxed at + * verification time. + */ + phone_number_condition?: 'allow_listed' | 'block_listed' | 'sandboxed'; + + /** + * Whether the phone number is currently allow-listed, block-listed, or sandboxed. + */ + phone_number_current_condition?: 'allow_listed' | 'block_listed' | 'sandboxed'; + + /** + * ISO 3166-1 alpha-2 region of the phone number. + */ + phone_number_region?: string; + + /** + * The anti-fraud signals you forwarded when creating the verification. + */ + signals?: HistoryRetrieveResponse.Signals; + + /** + * Whether the SDK signals integrity check passed. + */ + signals_hash_status?: 'valid' | 'invalid'; + + /** + * The template used for this verification. + */ + template_id?: string; +} + +export namespace HistoryRetrieveResponse { + /** + * Chronological timeline of the verification: creation, message attempts with + * delivery events, code checks and signals reception. Omitted when Prelude holds + * no timeline for the verification. + */ + export interface Lifecycle { + events: Array; + + total_cost?: HistoryAPI.PhoneVerificationMoney; + + /** + * How many times the message was reported undeliverable by independent routes. + * Above zero usually means the phone number is incorrect or the device + * unreachable. + */ + undeliverable_route_count?: number; + } + + export namespace Lifecycle { + /** + * One timeline entry. `type` names the single payload field that is set. + */ + export interface Event { + type: 'create' | 'attempt' | 'check' | 'signals'; + + /** + * One message sent for this verification. + */ + attempt?: Event.Attempt; + + /** + * One code submission for this verification. + */ + check?: Event.Check; + + create?: Event.Create; + + signals?: Event.Signals; + } + + export namespace Event { + /** + * One message sent for this verification. + */ + export interface Attempt { + id: string; + + created_at: string; + + /** + * The end user's mobile network. + */ + carrier?: HistoryAPI.PhoneVerificationCarrier; + + channel?: 'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram' | 'voice' | 'silent'; + + /** + * Message body. While the verification can still be completed, the code inside it + * is masked rather than removed. + */ + content?: string; + + cost?: HistoryAPI.PhoneVerificationMoney; + + delivery_events?: Array; + + delivery_status?: 'unknown' | 'in_transit' | 'delivered' | 'undeliverable' | 'read'; + + /** + * Channel you asked for, when it differs from the one used. + */ + preferred_channel?: 'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram' | 'voice' | 'silent'; + + status?: 'succeeded' | 'failed'; + + /** + * What caused the attempt. + */ + trigger?: 'initial' | 'auto_retry' | 'user_retry'; + } + + export namespace Attempt { + export interface DeliveryEvent { + received_at: string; + + /** + * The state this event reported. It is finer-grained than the attempt's + * `delivery_status` and includes the states a silent verification goes through. + */ + status: + | 'unknown' + | 'submitted' + | 'in_transit' + | 'delivered' + | 'undeliverable' + | 'expired' + | 'read' + | 'silent_started' + | 'silent_verified' + | 'silent_mismatch'; + } + } + + /** + * One code submission for this verification. + */ + export interface Check { + created_at: string; + + is_valid: boolean; + + channel?: 'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram' | 'voice' | 'silent'; + + /** + * Present on checks against a `prelude:psd2` code. + */ + psd2_info?: Check.Psd2Info; + + /** + * Why an invalid check failed, when known. + */ + status_detail?: + | 'expired_attempt' + | 'expired_auth' + | 'rate_limited' + | 'transaction_missing' + | 'transaction_mismatch'; + + /** + * The submitted code. Absent while the verification can still be completed, so + * that a check in flight cannot be read back through this endpoint, and absent on + * silent verification checks, which carry no code. + */ + value?: string; + } + + export namespace Check { + /** + * Present on checks against a `prelude:psd2` code. + */ + export interface Psd2Info { + /** + * The transaction submitted when the code was issued. + */ + expected_transaction?: HistoryAPI.PhoneVerificationPsd2Transaction; + + /** + * The transaction submitted with this check. Differs from `expected_transaction` + * when `status_detail` is `transaction_mismatch`. + */ + received_transaction?: HistoryAPI.PhoneVerificationPsd2Transaction; + } + } + + export interface Create { + created_at: string; + + cost?: HistoryAPI.PhoneVerificationMoney; + } + + export interface Signals { + received_at: string; + + expired_at?: string; + + status?: 'valid' | 'invalid'; + } + } + } + + /** + * The anti-fraud signals you forwarded when creating the verification. + */ + export interface Signals { + /** + * Whether you flagged this end user as trusted when creating the verification. + * Declared by you, not computed by Prelude. + */ + is_trusted_user: boolean; + + /** + * End-user device identifier you forwarded. + */ + device_id?: string; + + /** + * TLS fingerprint you forwarded. + */ + ja4_fingerprint?: string; + + os_version?: string; + + user_agent?: string; + } +} + +export interface HistoryListResponse { + /** + * The page of verifications, most recent first. + */ + verifications: Array; + + /** + * Pagination cursor for the next page of results. Omitted if there are no more + * pages. + */ + next_cursor?: string; +} + +export namespace HistoryListResponse { + /** + * One entry of the verification history. + * [Get a phone verification](/verify/v2/api-reference/history/get-a-phone-verification) + * returns the full record. + */ + export interface Verification { + /** + * The verification identifier. + */ + id: string; + + /** + * The channels the verification could use, and which one the end user converted + * through. Empty when the verification used only channels this API does not list. + */ + channels: Array; + + created_at: string; + + /** + * Whether at least one message was reported delivered. + */ + delivered: boolean; + + /** + * The E.164 phone number the verification targeted. + */ + phone_number: string; + + /** + * The outcome of the verification. + * + * - `converted` - The end user submitted a valid code. + * - `not_converted` - The verification expired without a valid code. + * - `pending_check` - A code was delivered and Prelude is still waiting for a + * check. + * - `sent` - A code was sent and the verification window is still open. + * - `challenged` - The verification was restricted to non-SMS and non-voice + * channels. + * - `suspected_fraud` - The anti-fraud system blocked the verification. + * - `in_blocklist` - The phone number is on the configured block list. + * - `invalid_line` - The phone number is not a valid line type. + * - `invalid_number` - The phone number is not a valid number. + * - `rate_limited` - The verification was refused by a rate limit. + * - `expired_signals` - The SDK signals were collected too long before the + * request. + * - `shadowed` - The anti-fraud system flagged the verification without blocking + * it. + */ + status: + | 'converted' + | 'not_converted' + | 'pending_check' + | 'sent' + | 'challenged' + | 'suspected_fraud' + | 'in_blocklist' + | 'invalid_line' + | 'invalid_number' + | 'rate_limited' + | 'expired_signals' + | 'shadowed'; + + /** + * Number of messages sent for the verification, `0` when none was. Absent for + * sandboxed phone numbers. + */ + attempts?: number; + + /** + * When the end user submitted a valid code. Absent unless the verification + * converted. + */ + converted_at?: string; + + /** + * Total cost of the verification. Absent when nothing was billed. + */ + cost?: HistoryAPI.PhoneVerificationMoney; + + /** + * Platform of the end-user device, when known. + */ + device_platform?: 'android' | 'ios' | 'ipados' | 'tvos' | 'web'; + + /** + * Whether the phone number was allow-listed, block-listed, or sandboxed at + * verification time. + */ + phone_number_condition?: 'allow_listed' | 'block_listed' | 'sandboxed'; + + /** + * Whether the SDK signals integrity check passed. + */ + signals_hash_status?: 'valid' | 'invalid'; + } + + export namespace Verification { + export interface Channel { + channel: 'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram' | 'voice' | 'silent'; + + /** + * Whether the end user submitted a valid code received through this channel. + */ + converted: boolean; + } + } +} + +export interface HistoryListParams { + /** + * Only verifications that could use one of these channels. Repeat the parameter + * for several values. + */ + channels?: Array<'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram' | 'voice' | 'silent'>; + + /** + * Pagination cursor from the previous response. + */ + cursor?: string; + + /** + * Only verifications created from this device platform. + */ + device_platform?: 'android' | 'ios' | 'ipados' | 'tvos' | 'web'; + + /** + * Only verifications created at or after this RFC 3339 timestamp. Goes with `to`, + * at most 6 months apart. Without them the whole history is searched. + */ + from?: string; + + /** + * Maximum number of verifications to return per page. + */ + limit?: number; + + /** + * Only verifications that sent at most this many messages. `0` keeps the + * verifications that never sent one. + */ + max_attempts?: number; + + /** + * Only verifications that sent at least this many messages. + */ + min_attempts?: number; + + /** + * Only verifications targeting this E.164 phone number. The leading `+` may be + * omitted. + */ + phone_number?: string; + + /** + * Only verifications of phone numbers from this region, as an ISO 3166-1 alpha-2 + * code. + */ + region?: string; + + /** + * Only verifications in this status. `pending_check` cannot be filtered on. + */ + status?: + | 'converted' + | 'not_converted' + | 'pending_check' + | 'sent' + | 'challenged' + | 'suspected_fraud' + | 'in_blocklist' + | 'invalid_line' + | 'invalid_number' + | 'rate_limited' + | 'expired_signals' + | 'shadowed'; + + /** + * Only verifications sent with this template, as returned in `template_id` by + * [Get a phone verification](/verify/v2/api-reference/history/get-a-phone-verification). + * Built-in templates (`prelude:*`) cannot be filtered on. + */ + template_id?: string; + + /** + * Only verifications created at or before this RFC 3339 timestamp. Goes with + * `from`. + */ + to?: string; +} + +export declare namespace History { + export { + type PhoneVerificationCarrier as PhoneVerificationCarrier, + type PhoneVerificationMoney as PhoneVerificationMoney, + type PhoneVerificationPsd2Transaction as PhoneVerificationPsd2Transaction, + type HistoryRetrieveResponse as HistoryRetrieveResponse, + type HistoryListResponse as HistoryListResponse, + type HistoryListParams as HistoryListParams, + }; +} diff --git a/src/resources/verification/phone/index.ts b/src/resources/verification/phone/index.ts new file mode 100644 index 0000000..65bc643 --- /dev/null +++ b/src/resources/verification/phone/index.ts @@ -0,0 +1,12 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + History, + type PhoneVerificationCarrier, + type PhoneVerificationMoney, + type PhoneVerificationPsd2Transaction, + type HistoryRetrieveResponse, + type HistoryListResponse, + type HistoryListParams, +} from './history'; +export { Phone } from './phone'; diff --git a/src/resources/verification/phone/phone.ts b/src/resources/verification/phone/phone.ts new file mode 100644 index 0000000..c989f8c --- /dev/null +++ b/src/resources/verification/phone/phone.ts @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../resource'; +import * as HistoryAPI from './history'; +import { + History, + HistoryListParams, + HistoryListResponse, + HistoryRetrieveResponse, + PhoneVerificationCarrier, + PhoneVerificationMoney, + PhoneVerificationPsd2Transaction, +} from './history'; + +export class Phone extends APIResource { + history: HistoryAPI.History = new HistoryAPI.History(this._client); +} + +Phone.History = History; + +export declare namespace Phone { + export { + History as History, + type PhoneVerificationCarrier as PhoneVerificationCarrier, + type PhoneVerificationMoney as PhoneVerificationMoney, + type PhoneVerificationPsd2Transaction as PhoneVerificationPsd2Transaction, + type HistoryRetrieveResponse as HistoryRetrieveResponse, + type HistoryListResponse as HistoryListResponse, + type HistoryListParams as HistoryListParams, + }; +} diff --git a/src/resources/verification/verification.ts b/src/resources/verification/verification.ts new file mode 100644 index 0000000..d61a62e --- /dev/null +++ b/src/resources/verification/verification.ts @@ -0,0 +1,465 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../resource'; +import * as Core from '../../core'; +import * as Shared from '../shared'; +import * as PhoneAPI from './phone/phone'; +import { Phone } from './phone/phone'; + +/** + * Verify phone numbers. + */ +export class Verification extends APIResource { + phone: PhoneAPI.Phone = new PhoneAPI.Phone(this._client); + + /** + * Create a new verification for a specific phone number. If another non-expired + * verification exists (the request is performed within the verification window), + * this endpoint will perform a retry instead. + * + * @example + * ```ts + * const verification = await client.verification.create({ + * target: { type: 'phone_number', value: '+30123456789' }, + * }); + * ``` + */ + create( + body: VerificationCreateParams, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.post('/v2/verification', { body, ...options }); + } + + /** + * Check the validity of a verification code. + * + * @example + * ```ts + * const response = await client.verification.check({ + * code: '12345', + * target: { type: 'phone_number', value: '+30123456789' }, + * }); + * ``` + */ + check( + body: VerificationCheckParams, + options?: Core.RequestOptions, + ): Core.APIPromise { + return this._client.post('/v2/verification/check', { body, ...options }); + } +} + +export interface VerificationCreateResponse { + /** + * The verification identifier. + */ + id: string; + + /** + * The method used for verifying this phone number. + */ + method: 'email' | 'message' | 'silent' | 'voice'; + + /** + * The status of the verification. + * + * - `success` - A new verification window was created. + * - `retry` - A new attempt was created for an existing verification window. + * - `challenged` - The verification is suspicious and is restricted to non-SMS and + * non-voice channels only. This mode must be enabled for your customer account + * by Prelude support. + * - `blocked` - The verification was blocked. + * - `shadow_blocked` - The verification triggered a block rule but the decision + * was not enforced; this is used to dry-run anti-fraud configuration. This mode + * must be enabled for your customer account by Prelude support. + */ + status: 'success' | 'retry' | 'challenged' | 'blocked' | 'shadow_blocked'; + + /** + * The ordered sequence of channels to be used for verification + */ + channels?: Array<'rcs' | 'silent' | 'sms' | 'telegram' | 'viber' | 'voice' | 'whatsapp' | 'zalo'>; + + /** + * The metadata for this verification. + */ + metadata?: VerificationCreateResponse.Metadata; + + /** + * The reason why the verification was blocked. Only present when status is + * "blocked" or "shadow_blocked". + * + * - `expired_signature` - The signature of the SDK signals is expired. They should + * be sent within the hour following their collection. + * - `in_block_list` - The phone number is part of the configured block list. + * - `invalid_phone_line` - The phone number is not a valid line number (e.g. + * landline). + * - `invalid_phone_number` - The phone number is not a valid phone number (e.g. + * unallocated range). + * - `invalid_signature` - The signature of the SDK signals is invalid. + * - `repeated_attempts` - The phone number has made too many verification + * attempts. + * - `suspicious` - The verification attempt was deemed suspicious by the + * anti-fraud system. + */ + reason?: + | 'expired_signature' + | 'in_block_list' + | 'invalid_phone_line' + | 'invalid_phone_number' + | 'invalid_signature' + | 'repeated_attempts' + | 'suspicious'; + + request_id?: string; + + /** + * The risk factors that contributed to the verification being blocked. Only + * present when status is "blocked" or "shadow_blocked" and the anti-fraud system + * detected specific risk signals. + * + * - `behavioral_pattern` - The phone number past behavior during verification + * flows exhibits suspicious patterns. + * - `device_attribute` - The device exhibits characteristics associated with + * suspicious activity patterns. + * - `fraud_database` - The phone number has been flagged as suspicious in one or + * more of our fraud databases. + * - `location_discrepancy` - The phone number prefix and IP address discrepancy + * indicates potential fraud. + * - `network_fingerprint` - The network connection exhibits characteristics + * associated with suspicious activity patterns. + * - `poor_conversion_history` - The phone number has a history of poorly + * converting to a verified phone number. + * - `prefix_concentration` - The phone number is part of a range known to be + * associated with suspicious activity patterns. + * - `suspected_request_tampering` - The SDK signature is invalid and the request + * is considered to be tampered with. + * - `suspicious_ip_address` - The IP address is deemed to be associated with + * suspicious activity patterns. + * - `temporary_phone_number` - The phone number is known to be a temporary or + * disposable number. + */ + risk_factors?: Array< + | 'behavioral_pattern' + | 'device_attribute' + | 'fraud_database' + | 'location_discrepancy' + | 'network_fingerprint' + | 'poor_conversion_history' + | 'prefix_concentration' + | 'suspected_request_tampering' + | 'suspicious_ip_address' + | 'temporary_phone_number' + >; + + /** + * The silent verification specific properties. + */ + silent?: VerificationCreateResponse.Silent; +} + +export namespace VerificationCreateResponse { + /** + * The metadata for this verification. + */ + export interface Metadata { + /** + * A user-defined identifier to correlate this verification with. It is returned in + * the response and any webhook events that refer to this verification. + */ + correlation_id?: string; + } + + /** + * The silent verification specific properties. + */ + export interface Silent { + /** + * The URL to start the silent verification towards. + */ + request_url: string; + } +} + +export interface VerificationCheckResponse { + /** + * The status of the check. For `prelude:psd2` codes, `transaction_missing` is + * returned when the `psd2` block is omitted, and `transaction_mismatch` when the + * submitted variables differ from those provided at issuance. + */ + status: 'success' | 'failure' | 'expired_or_not_found' | 'transaction_missing' | 'transaction_mismatch'; + + /** + * The verification identifier. + */ + id?: string; + + /** + * The metadata for this verification. + */ + metadata?: VerificationCheckResponse.Metadata; + + request_id?: string; +} + +export namespace VerificationCheckResponse { + /** + * The metadata for this verification. + */ + export interface Metadata { + /** + * A user-defined identifier to correlate this verification with. It is returned in + * the response and any webhook events that refer to this verification. + */ + correlation_id?: string; + } +} + +export interface VerificationCreateParams { + /** + * The verification target. Either a phone number or an email address. To use the + * email verification feature contact us to discuss your use case. + */ + target: Shared.Target; + + /** + * The identifier of the dispatch that came from the front-end SDK. + */ + dispatch_id?: string; + + /** + * The metadata for this verification. This object will be returned with every + * response or webhook sent that refers to this verification. + */ + metadata?: VerificationCreateParams.Metadata; + + /** + * Verification options + */ + options?: VerificationCreateParams.Options; + + /** + * The signals used for anti-fraud. For more details, refer to + * [Signals](/verify/v2/documentation/prevent-fraud#signals). + */ + signals?: Shared.Signals; +} + +export namespace VerificationCreateParams { + /** + * The metadata for this verification. This object will be returned with every + * response or webhook sent that refers to this verification. + */ + export interface Metadata { + /** + * A user-defined identifier to correlate this verification with. It is returned in + * the response and any webhook events that refer to this verification. + */ + correlation_id?: string; + } + + /** + * Verification options + */ + export interface Options { + /** + * This allows automatic OTP retrieval on mobile apps and web browsers. Supported + * platforms are Android (SMS Retriever API) and Web (WebOTP API). + */ + app_realm?: Options.AppRealm; + + /** + * The URL where webhooks will be sent when verification events occur, including + * verification creation, attempt creation, and delivery status changes. For more + * details, refer to [Webhook](/verify/v2/documentation/webhook). + */ + callback_url?: string; + + /** + * The channels this verification may use, in the order they are tried. Channels + * you omit are never used, including on retries. This option can only be set when + * the verification is created. The list is recorded on the verification and + * applies for its whole lifecycle, so `channels` sent while retrying an existing + * verification is ignored — unlike `preferred_channel`, which is honored on every + * retry. Every channel you list must be enabled on your account and active in the + * destination country, otherwise the request fails with + * `channel_not_enabled_in_region`. Prelude still picks the best provider within + * each channel. Cannot be combined with `preferred_channel`. Voice is requested + * through `method` instead. Disabled by default — contact support to enable it. + */ + channels?: Array<'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram'>; + + /** + * The size of the code generated. It should be between 4 and 8. Defaults to the + * code size specified from the Dashboard. + */ + code_size?: number; + + /** + * The custom code to use for OTP verification. To use the custom code feature, + * contact us to enable it for your account. For more details, refer to + * [Custom Code](/verify/v2/documentation/custom-codes). + */ + custom_code?: string; + + /** + * When `true`, the verification is routed through challenge-safe channels + * (non-SMS/Voice) regardless of country eligibility or any antispam outcome. The + * resulting verification has `status: "challenged"`. Use this when you have your + * own signal that the request is suspicious and want stricter routing — the + * verification is **not** classified as fraud and does not contribute to + * anti-fraud counters or risk factors. This feature is disabled by default — + * contact Prelude support to enable it on your account. + */ + force_challenge?: boolean; + + /** + * A BCP-47 formatted locale string with the language the text message will be sent + * to. If there's no locale set, the language will be determined by the country + * code of the phone number. If the language specified doesn't exist, it defaults + * to US English. + */ + locale?: string; + + /** + * Maximum number of delivery attempts Prelude may add on its own after the one you + * requested. `0` means a single attempt: if it cannot be delivered, Prelude + * neither tries another provider nor another channel, and does not retry + * automatically. `1` allows one additional attempt, and so on — a value larger + * than the number of routes available for the destination simply behaves like the + * default. When omitted, Prelude retries as your account is configured, across as + * many channels as the route offers. + * + * This option can only be set when the verification is created. The value is + * recorded on the verification and applies for its whole lifecycle, so a + * `max_auto_fallbacks` sent while retrying an existing verification is ignored — + * the limit cannot be raised or lowered after the fact. A retry you ask for is not + * an automatic attempt, so it gets a fresh allowance of the same limit. This + * option is disabled by default — contact Prelude support to enable it on your + * account. + */ + max_auto_fallbacks?: number; + + /** + * The method used for verifying this phone number. The 'voice' option provides an + * accessible alternative for visually impaired users by delivering the + * verification code through a phone call rather than a text message. It also + * allows verification of landline numbers that cannot receive SMS messages. The + * 'message' option explicitly requests message delivery (SMS, WhatsApp ...) and + * skips silent verification, useful for scenarios requiring direct user + * interaction. + */ + method?: 'auto' | 'voice' | 'message'; + + /** + * The channel to prioritize when delivering the verification. Prelude prioritizes + * this channel on the first attempt and continues to prefer it on retries while an + * untried route on that channel remains; once those are exhausted, retries fall + * back to the next best available route. If the channel is unavailable (for + * example, when a verification is challenged), Prelude uses the best available + * route instead. Cannot be combined with `channels`. + */ + preferred_channel?: 'sms' | 'rcs' | 'whatsapp' | 'viber' | 'zalo' | 'telegram'; + + /** + * The Sender ID to use for this message. The Sender ID needs to be enabled by + * Prelude. + */ + sender_id?: string; + + /** + * The identifier of a verification template. It applies use case-specific + * settings, such as the message content or certain verification parameters. + */ + template_id?: string; + + /** + * The variables to be replaced in the template. + */ + variables?: { [key: string]: string }; + } + + export namespace Options { + /** + * This allows automatic OTP retrieval on mobile apps and web browsers. Supported + * platforms are Android (SMS Retriever API) and Web (WebOTP API). + */ + export interface AppRealm { + /** + * The platform for automatic OTP retrieval. Use "android" for the SMS Retriever + * API or "web" for the WebOTP API. + */ + platform: 'android' | 'web'; + + /** + * The value depends on the platform: + * + * - For Android: The SMS Retriever API hash code (11 characters). See + * [Google documentation](https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string). + * - For Web: The origin domain (e.g., "example.com" or "www.example.com"). See + * [WebOTP API documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API). + */ + value: string; + } + } +} + +export interface VerificationCheckParams { + /** + * The OTP code to validate. + */ + code: string; + + /** + * The verification target. Either a phone number or an email address. To use the + * email verification feature contact us to discuss your use case. + */ + target: Shared.Target; + + /** + * Required when checking a code issued under the `prelude:psd2` template. The + * submitted variables must match those provided at issuance; any mismatch + * invalidates the code (PSD2 SCA RTS Article 5 dynamic linking). Ignored on + * non-PSD2 verifications. + */ + psd2?: VerificationCheckParams.Psd2; +} + +export namespace VerificationCheckParams { + /** + * Required when checking a code issued under the `prelude:psd2` template. The + * submitted variables must match those provided at issuance; any mismatch + * invalidates the code (PSD2 SCA RTS Article 5 dynamic linking). Ignored on + * non-PSD2 verifications. + */ + export interface Psd2 { + /** + * Decimal amount of the transaction. + */ + amount: string; + + /** + * ISO 4217 currency code. + */ + currency: string; + + /** + * Payee name displayed to the payer. + */ + recipient: string; + } +} + +Verification.Phone = Phone; + +export declare namespace Verification { + export { + type VerificationCreateResponse as VerificationCreateResponse, + type VerificationCheckResponse as VerificationCheckResponse, + type VerificationCreateParams as VerificationCreateParams, + type VerificationCheckParams as VerificationCheckParams, + }; + + export { Phone as Phone }; +} diff --git a/src/resources/watch.ts b/src/resources/watch.ts index e2c7f19..9da25ba 100644 --- a/src/resources/watch.ts +++ b/src/resources/watch.ts @@ -2,11 +2,37 @@ import { APIResource } from '../resource'; import * as Core from '../core'; +import * as Shared from './shared'; /** * Evaluate email addresses and phone numbers for trustworthiness. */ export class Watch extends APIResource { + /** + * **Beta.** The request and response shapes may still change, and flows and + * recipes are configured by Prelude on your behalf for now. Talk to us before you + * build against it. + * + * Score a target against the rules configured for one moment in your product — + * signup, checkout, password reset. The flow selects which recipes run; each + * recipe scores its rules against a threshold and returns its own verdict, and the + * evaluation answers with the most severe verdict and action across them. Where + * Predict returns a single model-derived outcome, Eval returns the full breakdown, + * so you can see which rules fired and which could not run. Scoring-only — it does + * not update counters by itself. + * + * @example + * ```ts + * const response = await client.watch.evaluate({ + * flow_id: 'flo_01jc0t6fwwfgfsq1md24mhyztj', + * target: { type: 'phone_number', value: '+30123456789' }, + * }); + * ``` + */ + evaluate(body: WatchEvaluateParams, options?: Core.RequestOptions): Core.APIPromise { + return this._client.post('/v2/watch/eval', { body, ...options }); + } + /** * At signup, score the user's phone number or email address (target) as legitimate * or suspicious. Scoring-only — does not update counters by itself. When using @@ -88,6 +114,135 @@ export class Watch extends APIResource { } } +export interface WatchEvaluateResponse { + /** + * The evaluation identifier. + */ + id: string; + + /** + * What the evaluation suggests you do, being the most severe action across the + * recipes that ran. Advisory: enforcement is yours. + * + * - `ALLOW` - Let the request through. + * - `BLOCK` - Refuse the request. + * - `CHALLENGE` - Let the request through behind an additional check. + */ + action: 'ALLOW' | 'BLOCK' | 'CHALLENGE'; + + /** + * One result per recipe that ran. A recipe the flow names but that is not in + * service is absent rather than reported as having passed. + */ + recipes: Array; + + /** + * The evaluation-level verdict, being the most severe verdict across the recipes + * that ran. + * + * - `PASS` - No recipe flagged. + * - `FLAG` - At least one recipe flagged. + */ + verdict: 'PASS' | 'FLAG'; +} + +export namespace WatchEvaluateResponse { + export interface Recipe { + /** + * At least one rule could not be evaluated, so the score rests on less than the + * whole recipe. The score is still returned — a partial verdict is more useful + * than none — but it is labeled rather than passed off as whole. + */ + partial_evidence: boolean; + + /** + * The recipe that produced this result. + */ + recipe_id: string; + + /** + * One result per rule in the recipe, in membership order. Every rule runs — a + * score is only meaningful when complete, so there is no short-circuit on the + * first trigger. + */ + rules: Array; + + /** + * The sum of the weights of the rules that triggered, clamped to the range -100 + * to 100. Two scores at a bound are not comparable. + */ + score: number; + + /** + * The score at or above which this recipe flags. + */ + threshold: number; + + /** + * This recipe's own verdict. Normally the score against the threshold, unless a + * preempting rule fired — see `determined_by`. + */ + verdict: 'PASS' | 'FLAG'; + + /** + * The preempting rule that set `verdict`, present only when a rule rather than the + * score decided it. Without it a recipe can report a score under its threshold and + * still flag, with nothing in the payload accounting for the difference. + */ + determined_by?: string; + } + + export namespace Recipe { + export interface Rule { + /** + * What the rule concluded. + * + * - `TRIGGERED` - The condition held; `weight` was added to the score. + * - `NOT_TRIGGERED` - The condition did not hold. + * - `NOT_EVALUATED` - The rule could not run, because something it reads never + * arrived. This is not a quieter `NOT_TRIGGERED`: it contributed nothing either + * way, and it is why `partial_evidence` is set on the recipe. + */ + outcome: 'TRIGGERED' | 'NOT_TRIGGERED' | 'NOT_EVALUATED'; + + /** + * The rule that produced this result. Present whatever the rule's visibility, so a + * rule you cannot see the condition of is still one you can reweight, switch off, + * or ask us about. + */ + rule_id: string; + + /** + * What this rule contributes to the recipe's score when it triggers. + */ + weight: number; + + /** + * Why the rule could not run, set only when `outcome` is `NOT_EVALUATED`. + * + * A rule you authored names the signal or attribute it waited on, since you wrote + * the expression that reads it. A Prelude-managed rule reports `missing_data` and + * nothing more: the signal it waited on is part of a condition that is not + * disclosed. + */ + blocked_by?: string; + + /** + * The rule's name, present for a rule you authored and omitted for a + * Prelude-managed one. A managed rule's name describes what it looks for, which is + * as much of the condition as the expression is. + */ + name?: string; + + /** + * The rule could not run for a reason on our side rather than anything about your + * request. `outcome` is `NOT_EVALUATED` and the failure is ours to fix. + */ + unavailable?: boolean; + } + } +} + export interface WatchPredictResponse { /** * The prediction identifier. @@ -175,125 +330,77 @@ export interface WatchSendFeedbacksResponse { status: 'success'; } -export interface WatchPredictParams { +export interface WatchEvaluateParams { /** - * The signup identifier to score — a phone number or email address. + * The flow to evaluate. A flow names the moment you are guarding and selects the + * recipes that run. */ - target: WatchPredictParams.Target; + flow_id: string; /** - * The identifier of the dispatch that came from the front-end SDK. + * The identifier to score — a phone number or email address. */ - dispatch_id?: string; + target: Shared.Target; /** - * The metadata for this prediction. + * Values for the attributes the flow's recipes declare, keyed without the `attr.` + * namespace a rule uses to reference them. + * + * An attribute a recipe declares and this request omits is treated as missing + * evidence, not as an empty value: the rules reading it report `NOT_EVALUATED` + * rather than being scored as though the condition were false. A key no recipe in + * the flow declares is ignored rather than rejected, so one payload can serve + * flows that read different attributes. */ - metadata?: WatchPredictParams.Metadata; + attributes?: { [key: string]: string }; + + /** + * The identifier of the dispatch that came from the front-end SDK. Signals it + * carries fill in anything the request did not state; the request wins where both + * supply a value. + */ + dispatch_id?: string; /** * The signals used for anti-fraud. For more details, refer to * [Signals](/verify/v2/documentation/prevent-fraud#signals). */ - signals?: WatchPredictParams.Signals; + signals?: Shared.Signals; } -export namespace WatchPredictParams { +export interface WatchPredictParams { /** * The signup identifier to score — a phone number or email address. */ - export interface Target { - /** - * The type of the target. Either "phone_number" or "email_address". - */ - type: 'phone_number' | 'email_address'; + target: Shared.Target; - /** - * An E.164 formatted phone number or an email address. - */ - value: string; - } + /** + * The identifier of the dispatch that came from the front-end SDK. + */ + dispatch_id?: string; /** * The metadata for this prediction. */ - export interface Metadata { - /** - * A user-defined identifier to correlate this prediction with. It is returned in - * the response and any webhook events that refer to this prediction. - */ - correlation_id?: string; - } + metadata?: WatchPredictParams.Metadata; /** * The signals used for anti-fraud. For more details, refer to * [Signals](/verify/v2/documentation/prevent-fraud#signals). */ - export interface Signals { - /** - * The version of your application. - */ - app_version?: string; - - /** - * A unique ID for the user's device. You should ensure that each user device has a - * unique `device_id` value. Ideally, for Android, this corresponds to the - * `ANDROID_ID` and for iOS, this corresponds to the `identifierForVendor`. - */ - device_id?: string; - - /** - * The model of the user's device. - */ - device_model?: string; - - /** - * The type of the user's device. - */ - device_platform?: 'android' | 'ios' | 'ipados' | 'tvos' | 'web'; - - /** - * Whether the end-user already exists in your system, for example an existing - * account signing in again rather than a first-time signup. Unlike - * `is_trusted_user`, this signal does not bypass fraud checks; it is taken into - * account as one additional anti-fraud signal. For more details, refer to - * [Signals](/verify/v2/documentation/prevent-fraud#signals). - */ - existing_user?: boolean; - - /** - * The public IP v4 or v6 address of the end-user's device. You should collect this - * from your backend. If your backend is behind a proxy, use the `X-Forwarded-For`, - * `Forwarded`, `True-Client-IP`, `CF-Connecting-IP` or an equivalent header to get - * the actual public IP of the end-user's device. - */ - ip?: string; - - /** - * This signal should indicate a higher level of trust, explicitly stating that the - * user is genuine. Contact us to discuss your use case. For more details, refer to - * [Signals](/verify/v2/documentation/prevent-fraud#signals). - */ - is_trusted_user?: boolean; - - /** - * The JA4 fingerprint observed for the end-user's connection. Prelude will infer - * it automatically when you use our Frontend SDKs (which use Prelude's edge - * network), but you can also forward the value if you terminate TLS yourself. - */ - ja4_fingerprint?: string; - - /** - * The version of the user's device operating system. - */ - os_version?: string; + signals?: Shared.Signals; +} +export namespace WatchPredictParams { + /** + * The metadata for this prediction. + */ + export interface Metadata { /** - * The user agent of the user's device. If the individual fields (os_version, - * device_platform, device_model) are provided, we will prioritize those values - * instead of parsing them from the user agent string. + * A user-defined identifier to correlate this prediction with. It is returned in + * the response and any webhook events that refer to this prediction. */ - user_agent?: string; + correlation_id?: string; } } @@ -328,24 +435,7 @@ export namespace WatchSendEventsParams { /** * The event target. Only supports phone numbers for now. */ - target: Event.Target; - } - - export namespace Event { - /** - * The event target. Only supports phone numbers for now. - */ - export interface Target { - /** - * The type of the target. Either "phone_number" or "email_address". - */ - type: 'phone_number' | 'email_address'; - - /** - * An E.164 formatted phone number or an email address. - */ - value: string; - } + target: Shared.Target; } } @@ -362,7 +452,7 @@ export namespace WatchSendFeedbacksParams { /** * The feedback target. Only supports phone numbers for now. */ - target: Feedback.Target; + target: Shared.Target; /** * The type of feedback. @@ -376,21 +466,6 @@ export namespace WatchSendFeedbacksParams { } export namespace Feedback { - /** - * The feedback target. Only supports phone numbers for now. - */ - export interface Target { - /** - * The type of the target. Either "phone_number" or "email_address". - */ - type: 'phone_number' | 'email_address'; - - /** - * An E.164 formatted phone number or an email address. - */ - value: string; - } - /** * The metadata for this feedback. */ @@ -406,9 +481,11 @@ export namespace WatchSendFeedbacksParams { export declare namespace Watch { export { + type WatchEvaluateResponse as WatchEvaluateResponse, type WatchPredictResponse as WatchPredictResponse, type WatchSendEventsResponse as WatchSendEventsResponse, type WatchSendFeedbacksResponse as WatchSendFeedbacksResponse, + type WatchEvaluateParams as WatchEvaluateParams, type WatchPredictParams as WatchPredictParams, type WatchSendEventsParams as WatchSendEventsParams, type WatchSendFeedbacksParams as WatchSendFeedbacksParams, diff --git a/tests/api-resources/intel/kyc.test.ts b/tests/api-resources/intel/kyc.test.ts new file mode 100644 index 0000000..1d51a6c --- /dev/null +++ b/tests/api-resources/intel/kyc.test.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Prelude from '@prelude.so/sdk'; +import { Response } from 'node-fetch'; + +const client = new Prelude({ + apiToken: 'My API Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource kyc', () => { + test('match', async () => { + const responsePromise = client.intel.kyc.match('+12065550100', {}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/notify.test.ts b/tests/api-resources/notify.test.ts index efe5754..61734e2 100644 --- a/tests/api-resources/notify.test.ts +++ b/tests/api-resources/notify.test.ts @@ -140,6 +140,31 @@ describe('resource notify', () => { ).rejects.toThrow(Prelude.NotFoundError); }); + test('reply: only required params', async () => { + const responsePromise = client.notify.reply({ + reply_to: 'im_01k8aq2zggeyssvt53zgvpx63a', + text: "Thanks for reaching out! We'll look into your request.", + to: '+33612345678', + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('reply: required and optional params', async () => { + const response = await client.notify.reply({ + reply_to: 'im_01k8aq2zggeyssvt53zgvpx63a', + text: "Thanks for reaching out! We'll look into your request.", + to: '+33612345678', + callback_url: 'https://your-app.com/webhooks/notify', + correlation_id: 'support-ticket-42', + }); + }); + test('send: only required params', async () => { const responsePromise = client.notify.send({ template_id: 'template_01k8ap1btqf5r9fq2c8ax5fhc9', diff --git a/tests/api-resources/verification-management/sandbox.test.ts b/tests/api-resources/verification-management/sandbox.test.ts new file mode 100644 index 0000000..69fa48c --- /dev/null +++ b/tests/api-resources/verification-management/sandbox.test.ts @@ -0,0 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Prelude from '@prelude.so/sdk'; +import { Response } from 'node-fetch'; + +const client = new Prelude({ + apiToken: 'My API Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource sandbox', () => { + test('addPhoneNumber: only required params', async () => { + const responsePromise = client.verificationManagement.sandbox.addPhoneNumber({ + attempt_code: '123456', + phone_number: '+30123456789', + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('addPhoneNumber: required and optional params', async () => { + const response = await client.verificationManagement.sandbox.addPhoneNumber({ + attempt_code: '123456', + phone_number: '+30123456789', + }); + }); + + test('deletePhoneNumber', async () => { + const responsePromise = client.verificationManagement.sandbox.deletePhoneNumber('+12065550100'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('deletePhoneNumber: request options instead of params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.verificationManagement.sandbox.deletePhoneNumber('+12065550100', { + path: '/_stainless_unknown_path', + }), + ).rejects.toThrow(Prelude.NotFoundError); + }); + + test('listPhoneNumbers', async () => { + const responsePromise = client.verificationManagement.sandbox.listPhoneNumbers(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('listPhoneNumbers: request options instead of params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.verificationManagement.sandbox.listPhoneNumbers({ path: '/_stainless_unknown_path' }), + ).rejects.toThrow(Prelude.NotFoundError); + }); +}); diff --git a/tests/api-resources/verification-management.test.ts b/tests/api-resources/verification-management/verification-management.test.ts similarity index 100% rename from tests/api-resources/verification-management.test.ts rename to tests/api-resources/verification-management/verification-management.test.ts diff --git a/tests/api-resources/verification/phone/history.test.ts b/tests/api-resources/verification/phone/history.test.ts new file mode 100644 index 0000000..5d989f5 --- /dev/null +++ b/tests/api-resources/verification/phone/history.test.ts @@ -0,0 +1,72 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Prelude from '@prelude.so/sdk'; +import { Response } from 'node-fetch'; + +const client = new Prelude({ + apiToken: 'My API Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource history', () => { + test('retrieve', async () => { + const responsePromise = client.verification.phone.history.retrieve('vrf_01jc0t6fwwfgfsq1md24mhyztj'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('retrieve: request options instead of params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.verification.phone.history.retrieve('vrf_01jc0t6fwwfgfsq1md24mhyztj', { + path: '/_stainless_unknown_path', + }), + ).rejects.toThrow(Prelude.NotFoundError); + }); + + test('list', async () => { + const responsePromise = client.verification.phone.history.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('list: request options instead of params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.verification.phone.history.list({ path: '/_stainless_unknown_path' }), + ).rejects.toThrow(Prelude.NotFoundError); + }); + + test('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.verification.phone.history.list( + { + channels: ['sms'], + cursor: 'cursor', + device_platform: 'android', + from: '2026-09-01T00:00:00Z', + limit: 1, + max_attempts: 0, + min_attempts: 0, + phone_number: '+33612345678', + region: 'FR', + status: 'converted', + template_id: 'template_01jc0t6fwwfgfsq1md24mhyztj', + to: '2026-09-08T00:00:00Z', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Prelude.NotFoundError); + }); +}); diff --git a/tests/api-resources/verification.test.ts b/tests/api-resources/verification/verification.test.ts similarity index 100% rename from tests/api-resources/verification.test.ts rename to tests/api-resources/verification/verification.test.ts diff --git a/tests/api-resources/watch.test.ts b/tests/api-resources/watch.test.ts index db4afe7..195dba5 100644 --- a/tests/api-resources/watch.test.ts +++ b/tests/api-resources/watch.test.ts @@ -9,6 +9,42 @@ const client = new Prelude({ }); describe('resource watch', () => { + test('evaluate: only required params', async () => { + const responsePromise = client.watch.evaluate({ + flow_id: 'flo_01jc0t6fwwfgfsq1md24mhyztj', + target: { type: 'phone_number', value: '+30123456789' }, + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('evaluate: required and optional params', async () => { + const response = await client.watch.evaluate({ + flow_id: 'flo_01jc0t6fwwfgfsq1md24mhyztj', + target: { type: 'phone_number', value: '+30123456789' }, + attributes: { plan_tier: 'free', account_age_days: '3' }, + dispatch_id: '123e4567-e89b-12d3-a456-426614174000', + signals: { + app_version: '1.2.34', + device_id: '8F0B8FDD-C2CB-4387-B20A-56E9B2E5A0D2', + device_model: 'iPhone17,2', + device_platform: 'ios', + existing_user: false, + ip: '203.0.113.123', + is_trusted_user: false, + ja4_fingerprint: 't13d1516h2_8daaf6152771_e5627efa2ab1', + os_version: '18.0.1', + user_agent: + 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1', + }, + }); + }); + test('predict: only required params', async () => { const responsePromise = client.watch.predict({ target: { type: 'phone_number', value: '+30123456789' } }); const rawResponse = await responsePromise.asResponse(); From cec93b10df8de60c923cbe9ca68e195c17b5fff6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 15:49:11 +0000 Subject: [PATCH 2/2] release: 0.15.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ package.json | 2 +- src/version.ts | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 727e2be..f87262a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.14.0" + ".": "0.15.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index a78939e..7cc44ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.15.0 (2026-09-18) + +Full Changelog: [v0.14.0...v0.15.0](https://github.com/prelude-so/node-sdk/compare/v0.14.0...v0.15.0) + +### Features + +* **api:** manual updates ([524243a](https://github.com/prelude-so/node-sdk/commit/524243a641cfb439443592613422465cefd1f8d3)) + ## 0.14.0 (2026-09-15) Full Changelog: [v0.13.0...v0.14.0](https://github.com/prelude-so/node-sdk/compare/v0.13.0...v0.14.0) diff --git a/package.json b/package.json index ccfa5ba..fe578ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@prelude.so/sdk", - "version": "0.14.0", + "version": "0.15.0", "description": "The official TypeScript library for the Prelude API", "author": "Prelude ", "types": "dist/index.d.ts", diff --git a/src/version.ts b/src/version.ts index e2b0672..b67001e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.14.0'; // x-release-please-version +export const VERSION = '0.15.0'; // x-release-please-version