diff --git a/api-reference-v2/api-reference/payments/payments--create-intent.mdx b/api-reference-v2/api-reference/payments/payments--create-intent.mdx new file mode 100644 index 0000000000..2562fb5781 --- /dev/null +++ b/api-reference-v2/api-reference/payments/payments--create-intent.mdx @@ -0,0 +1,3 @@ +--- +openapi: post /v2/payments/create-intent +--- \ No newline at end of file diff --git a/api-reference-v2/mint.json b/api-reference-v2/mint.json index ae48e2b8e7..4c053f4d96 100644 --- a/api-reference-v2/mint.json +++ b/api-reference-v2/mint.json @@ -34,6 +34,12 @@ "essentials/go-live" ] }, + { + "group": "Payments", + "pages": [ + "api-reference/payments/payments--create-intent" + ] + }, { "group": "Organization", "pages": [ diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index fb679970f3..cf930f4b4e 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -1653,6 +1653,56 @@ } ] } + }, + "/v2/payments/create-intent": { + "post": { + "tags": [ + "Payments" + ], + "summary": "Payments - Create Intent", + "description": "**Creates a payment intent object when amount_details are passed.**\n\nYou will require the 'API - Key' from the Hyperswitch dashboard to make the first call, and use the 'client secret' returned in this API along with your 'publishable key' to make subsequent API calls from your client.", + "operationId": "Create a Payment Intent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentsCreateIntentRequest" + }, + "examples": { + "Create a payment intent with minimal fields": { + "value": { + "amount_details": { + "currency": "USD", + "order_amount": 6540 + } + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Payment created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentsCreateIntentResponse" + } + } + } + }, + "400": { + "description": "Missing Mandatory fields" + } + }, + "security": [ + { + "api_key": [] + } + ] + } } }, "components": { @@ -2076,6 +2126,62 @@ "AliPayRedirection": { "type": "object" }, + "AmountDetails": { + "type": "object", + "required": [ + "currency" + ], + "properties": { + "order_amount": { + "type": "integer", + "format": "int64", + "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", + "example": 6540, + "minimum": 0 + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "shipping_cost": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "tax_details": { + "allOf": [ + { + "$ref": "#/components/schemas/TaxDetails" + } + ], + "nullable": true + }, + "skip_external_tax_calculation": { + "$ref": "#/components/schemas/TaxCalculationOverride" + }, + "skip_surcharge_calculation": { + "$ref": "#/components/schemas/SurchargeCalculationOverride" + }, + "surcharge_amount": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "tax_on_surcharge": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + } + } + }, "AmountFilter": { "type": "object", "properties": { @@ -6240,6 +6346,17 @@ } } }, + "DefaultTax": { + "type": "object", + "required": [ + "order_tax_amount" + ], + "properties": { + "order_tax_amount": { + "$ref": "#/components/schemas/MinorUnit" + } + } + }, "DeviceChannel": { "type": "string", "description": "Device Channel indicating whether request is coming from App or Browser", @@ -6499,6 +6616,14 @@ } } }, + "EnablePaymentLinkRequest": { + "type": "string", + "description": "Whether payment link is requested to be enabled or not for this transaction", + "enum": [ + "Enable", + "Skip" + ] + }, "EnabledPaymentMethod": { "type": "object", "description": "Object for EnabledPaymentMethod", @@ -6784,6 +6909,14 @@ } } }, + "External3dsAuthenticationRequest": { + "type": "string", + "description": "Whether 3ds authentication is requested or not", + "enum": [ + "Enable", + "Skip" + ] + }, "ExternalAuthenticationDetailsResponse": { "type": "object", "description": "Details of external authentication", @@ -9625,6 +9758,13 @@ "format": "int64", "description": "This Unit struct represents MinorUnit in which core amount works" }, + "MitExemptionRequest": { + "type": "string", + "enum": [ + "Apply", + "Skip" + ] + }, "MobilePayRedirection": { "type": "object" }, @@ -12150,6 +12290,21 @@ "open_banking_pis" ] }, + "PaymentMethodTypeTax": { + "type": "object", + "required": [ + "order_tax_amount", + "pmt" + ], + "properties": { + "order_tax_amount": { + "$ref": "#/components/schemas/MinorUnit" + }, + "pmt": { + "$ref": "#/components/schemas/PaymentMethodType" + } + } + }, "PaymentMethodUpdate": { "type": "object", "properties": { @@ -12733,6 +12888,324 @@ } } }, + "PaymentsCreateIntentRequest": { + "type": "object", + "required": [ + "amount_details" + ], + "properties": { + "amount_details": { + "$ref": "#/components/schemas/AmountDetails" + }, + "merchant_reference_id": { + "type": "string", + "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", + "example": "pay_mbabizu24mvu3mela5njyhpit4", + "nullable": true, + "maxLength": 30, + "minLength": 30 + }, + "routing_algorithm_id": { + "type": "string", + "description": "The routing algorithm id to be used for the payment", + "nullable": true + }, + "capture_method": { + "$ref": "#/components/schemas/CaptureMethod" + }, + "authentication_type": { + "allOf": [ + { + "$ref": "#/components/schemas/AuthenticationType" + } + ], + "default": "no_three_ds" + }, + "billing": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + } + ], + "nullable": true + }, + "shipping": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + } + ], + "nullable": true + }, + "customer_id": { + "type": "string", + "description": "The identifier for the customer", + "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", + "nullable": true, + "maxLength": 64, + "minLength": 1 + }, + "customer_present": { + "$ref": "#/components/schemas/PresenceOfCustomerDuringPayment" + }, + "description": { + "type": "string", + "description": "A description for the payment", + "example": "It's my first payment request", + "nullable": true + }, + "return_url": { + "type": "string", + "description": "The URL to which you want the user to be redirected after the completion of the payment operation", + "example": "https://hyperswitch.io", + "nullable": true + }, + "setup_future_usage": { + "$ref": "#/components/schemas/FutureUsage" + }, + "apply_mit_exemption": { + "$ref": "#/components/schemas/MitExemptionRequest" + }, + "statement_descriptor": { + "type": "string", + "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", + "example": "Hyperswitch Router", + "nullable": true, + "maxLength": 22 + }, + "order_details": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderDetailsWithAmount" + }, + "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", + "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", + "nullable": true + }, + "allowed_payment_method_types": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentMethodType" + }, + "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", + "nullable": true + }, + "metadata": { + "type": "object", + "description": "Metadata is useful for storing additional, unstructured information on an object.", + "nullable": true + }, + "connector_metadata": { + "allOf": [ + { + "$ref": "#/components/schemas/ConnectorMetadata" + } + ], + "nullable": true + }, + "feature_metadata": { + "allOf": [ + { + "$ref": "#/components/schemas/FeatureMetadata" + } + ], + "nullable": true + }, + "payment_link_enabled": { + "$ref": "#/components/schemas/EnablePaymentLinkRequest" + }, + "payment_link_config": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentCreatePaymentLinkConfig" + } + ], + "nullable": true + }, + "request_incremental_authorization": { + "$ref": "#/components/schemas/RequestIncrementalAuthorization" + }, + "session_expiry": { + "type": "integer", + "format": "int32", + "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds, if not sent it will be taken from profile config\n(900) for 15 mins", + "example": 900, + "nullable": true, + "minimum": 0 + }, + "frm_metadata": { + "type": "object", + "description": "Additional data related to some frm(Fraud Risk Management) connectors", + "nullable": true + }, + "request_external_three_ds_authentication": { + "$ref": "#/components/schemas/External3dsAuthenticationRequest" + } + }, + "additionalProperties": false + }, + "PaymentsCreateIntentResponse": { + "type": "object", + "required": [ + "amount_details" + ], + "properties": { + "amount_details": { + "$ref": "#/components/schemas/AmountDetails" + }, + "client_secret": { + "type": "string", + "description": "It's a token used for client side verification.", + "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo", + "nullable": true + }, + "merchant_reference_id": { + "type": "string", + "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", + "example": "pay_mbabizu24mvu3mela5njyhpit4", + "nullable": true, + "maxLength": 30, + "minLength": 30 + }, + "routing_algorithm_id": { + "type": "string", + "description": "The routing algorithm id to be used for the payment", + "nullable": true + }, + "capture_method": { + "$ref": "#/components/schemas/CaptureMethod" + }, + "authentication_type": { + "allOf": [ + { + "$ref": "#/components/schemas/AuthenticationType" + } + ], + "default": "no_three_ds" + }, + "billing": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + } + ], + "nullable": true + }, + "shipping": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + } + ], + "nullable": true + }, + "customer_id": { + "type": "string", + "description": "The identifier for the customer", + "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", + "nullable": true, + "maxLength": 64, + "minLength": 1 + }, + "customer_present": { + "$ref": "#/components/schemas/PresenceOfCustomerDuringPayment" + }, + "description": { + "type": "string", + "description": "A description for the payment", + "example": "It's my first payment request", + "nullable": true + }, + "return_url": { + "type": "string", + "description": "The URL to which you want the user to be redirected after the completion of the payment operation", + "example": "https://hyperswitch.io", + "nullable": true + }, + "setup_future_usage": { + "$ref": "#/components/schemas/FutureUsage" + }, + "apply_mit_exemption": { + "$ref": "#/components/schemas/MitExemptionRequest" + }, + "statement_descriptor": { + "type": "string", + "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", + "example": "Hyperswitch Router", + "nullable": true, + "maxLength": 22 + }, + "order_details": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderDetailsWithAmount" + }, + "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", + "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", + "nullable": true + }, + "allowed_payment_method_types": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentMethodType" + }, + "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", + "nullable": true + }, + "metadata": { + "type": "object", + "description": "Metadata is useful for storing additional, unstructured information on an object.", + "nullable": true + }, + "connector_metadata": { + "allOf": [ + { + "$ref": "#/components/schemas/ConnectorMetadata" + } + ], + "nullable": true + }, + "feature_metadata": { + "allOf": [ + { + "$ref": "#/components/schemas/FeatureMetadata" + } + ], + "nullable": true + }, + "payment_link_enabled": { + "$ref": "#/components/schemas/EnablePaymentLinkRequest" + }, + "payment_link_config": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentCreatePaymentLinkConfig" + } + ], + "nullable": true + }, + "request_incremental_authorization": { + "$ref": "#/components/schemas/RequestIncrementalAuthorization" + }, + "session_expiry": { + "type": "integer", + "format": "int32", + "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins", + "example": 900, + "nullable": true, + "minimum": 0 + }, + "frm_metadata": { + "type": "object", + "description": "Additional data related to some frm(Fraud Risk Management) connectors", + "nullable": true + }, + "request_external_three_ds_authentication": { + "$ref": "#/components/schemas/External3dsAuthenticationRequest" + } + }, + "additionalProperties": false + }, "PaymentsCreateRequest": { "type": "object", "required": [ @@ -16421,6 +16894,14 @@ "not_found" ] }, + "PresenceOfCustomerDuringPayment": { + "type": "string", + "description": "Set to true to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be false when merchant's doing merchant initiated payments and customer is not present while doing the payment.", + "enum": [ + "Present", + "Absent" + ] + }, "PrimaryBusinessDetails": { "type": "object", "required": [ @@ -17358,6 +17839,14 @@ }, "additionalProperties": false }, + "RequestIncrementalAuthorization": { + "type": "string", + "enum": [ + "true", + "false", + "default" + ] + }, "RequestPaymentMethodTypes": { "type": "object", "required": [ @@ -18620,6 +19109,13 @@ "destination" ] }, + "SurchargeCalculationOverride": { + "type": "string", + "enum": [ + "Skip", + "Calculate" + ] + }, "SurchargeDetailsResponse": { "type": "object", "required": [ @@ -18721,6 +19217,34 @@ "SwishQrData": { "type": "object" }, + "TaxCalculationOverride": { + "type": "string", + "enum": [ + "Skip", + "Calculate" + ] + }, + "TaxDetails": { + "type": "object", + "properties": { + "default": { + "allOf": [ + { + "$ref": "#/components/schemas/DefaultTax" + } + ], + "nullable": true + }, + "payment_method_type": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentMethodTypeTax" + } + ], + "nullable": true + } + } + }, "ThirdPartySdkSessionResponse": { "type": "object", "required": [ diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 23c3b219b6..a2ae6e950f 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -114,6 +114,298 @@ pub struct CustomerDetailsResponse { pub phone_country_code: Option, } +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] +#[serde(deny_unknown_fields)] +#[cfg(feature = "v2")] +pub struct PaymentsCreateIntentRequest { + /// The amount details for the payment + pub amount_details: AmountDetails, + + /// Unique identifier for the payment. This ensures idempotency for multiple payments + /// that have been done by a single merchant. + #[schema( + value_type = Option, + min_length = 30, + max_length = 30, + example = "pay_mbabizu24mvu3mela5njyhpit4" + )] + pub merchant_reference_id: Option, + + /// The routing algorithm id to be used for the payment + #[schema(value_type = Option)] + pub routing_algorithm_id: Option, + + #[schema(value_type = CaptureMethod, example = "automatic")] + #[serde(default)] + pub capture_method: api_enums::CaptureMethod, + + #[schema(value_type = AuthenticationType, example = "no_three_ds", default = "no_three_ds")] + #[serde(default)] + pub authentication_type: api_enums::AuthenticationType, + + /// The billing details of the payment. This address will be used for invoicing. + pub billing: Option
, + + /// The shipping address for the payment + pub shipping: Option
, + + /// The identifier for the customer + #[schema(value_type = Option, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")] + pub customer_id: Option, + + /// Set to true to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be false when merchant's doing merchant initiated payments and customer is not present while doing the payment. + #[schema(example = true, value_type = PresenceOfCustomerDuringPayment)] + #[serde(default)] + pub customer_present: common_enums::PresenceOfCustomerDuringPayment, + + /// A description for the payment + #[schema(example = "It's my first payment request", value_type = Option)] + pub description: Option, + + /// The URL to which you want the user to be redirected after the completion of the payment operation + #[schema(value_type = Option, example = "https://hyperswitch.io")] + pub return_url: Option, + + #[schema(value_type = FutureUsage, example = "off_session")] + #[serde(default)] + pub setup_future_usage: api_enums::FutureUsage, + + /// Apply MIT exemption for a payment + #[schema(value_type = MitExemptionRequest)] + #[serde(default)] + pub apply_mit_exemption: common_enums::MitExemptionRequest, + + /// For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. + #[schema(max_length = 22, example = "Hyperswitch Router", value_type = Option)] + pub statement_descriptor: Option, + + /// Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount + #[schema(value_type = Option>, example = r#"[{ + "product_name": "Apple iPhone 16", + "quantity": 1, + "amount" : 69000 + "product_img_link" : "https://dummy-img-link.com" + }]"#)] + pub order_details: Option>, + + /// Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent + #[schema(value_type = Option>)] + pub allowed_payment_method_types: Option>, + + /// Metadata is useful for storing additional, unstructured information on an object. + #[schema(value_type = Option, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)] + pub metadata: Option, + + /// Some connectors like Apple pay, Airwallex and Noon might require some additional information, find specific details in the child attributes below. + pub connector_metadata: Option, + + /// Additional data that might be required by hyperswitch based on the requested features by the merchants. + pub feature_metadata: Option, + + /// Whether to generate the payment link for this payment or not (if applicable) + #[schema(value_type = EnablePaymentLinkRequest)] + #[serde(default)] + pub payment_link_enabled: common_enums::EnablePaymentLinkRequest, + + /// Configure a custom payment link for the particular payment + #[schema(value_type = Option)] + pub payment_link_config: Option, + + ///Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it. + #[schema(value_type = RequestIncrementalAuthorization)] + #[serde(default)] + pub request_incremental_authorization: common_enums::RequestIncrementalAuthorization, + + ///Will be used to expire client secret after certain amount of time to be supplied in seconds, if not sent it will be taken from profile config + ///(900) for 15 mins + #[schema(example = 900)] + pub session_expiry: Option, + + /// Additional data related to some frm(Fraud Risk Management) connectors + #[schema(value_type = Option, example = r#"{ "coverage_request" : "fraud", "fulfillment_method" : "delivery" }"#)] + pub frm_metadata: Option, + + /// Whether to perform external authentication (if applicable) + #[schema(value_type = External3dsAuthenticationRequest)] + #[serde(default)] + pub request_external_three_ds_authentication: common_enums::External3dsAuthenticationRequest, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] +#[serde(deny_unknown_fields)] +#[cfg(feature = "v2")] +pub struct PaymentsCreateIntentResponse { + /// The amount details for the payment + pub amount_details: AmountDetails, + + /// It's a token used for client side verification. + #[schema(value_type = Option, example = "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo")] + pub client_secret: Option>, + + /// Unique identifier for the payment. This ensures idempotency for multiple payments + /// that have been done by a single merchant. + #[schema( + value_type = Option, + min_length = 30, + max_length = 30, + example = "pay_mbabizu24mvu3mela5njyhpit4" + )] + pub merchant_reference_id: Option, + + /// The routing algorithm id to be used for the payment + #[schema(value_type = Option)] + pub routing_algorithm_id: Option, + + #[schema(value_type = CaptureMethod, example = "automatic")] + #[serde(default)] + pub capture_method: api_enums::CaptureMethod, + + #[schema(value_type = AuthenticationType, example = "no_three_ds", default = "no_three_ds")] + #[serde(default)] + pub authentication_type: api_enums::AuthenticationType, + + /// The billing details of the payment. This address will be used for invoicing. + pub billing: Option
, + + /// The shipping address for the payment + pub shipping: Option
, + + /// The identifier for the customer + #[schema(value_type = Option, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")] + pub customer_id: Option, + + /// Set to true to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be false when merchant's doing merchant initiated payments and customer is not present while doing the payment. + #[schema(example = true, value_type = PresenceOfCustomerDuringPayment)] + #[serde(default)] + pub customer_present: common_enums::PresenceOfCustomerDuringPayment, + + /// A description for the payment + #[schema(example = "It's my first payment request", value_type = Option)] + pub description: Option, + + /// The URL to which you want the user to be redirected after the completion of the payment operation + #[schema(value_type = Option, example = "https://hyperswitch.io")] + pub return_url: Option, + + #[schema(value_type = FutureUsage, example = "off_session")] + #[serde(default)] + pub setup_future_usage: api_enums::FutureUsage, + + /// Apply MIT exemption for a payment + #[schema(value_type = MitExemptionRequest)] + #[serde(default)] + pub apply_mit_exemption: common_enums::MitExemptionRequest, + + /// For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. + #[schema(max_length = 22, example = "Hyperswitch Router", value_type = Option)] + pub statement_descriptor: Option, + + /// Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount + #[schema(value_type = Option>, example = r#"[{ + "product_name": "Apple iPhone 16", + "quantity": 1, + "amount" : 69000 + "product_img_link" : "https://dummy-img-link.com" + }]"#)] + pub order_details: Option>, + + /// Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent + #[schema(value_type = Option>)] + pub allowed_payment_method_types: Option>, + + /// Metadata is useful for storing additional, unstructured information on an object. + #[schema(value_type = Option, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)] + pub metadata: Option, + + /// Some connectors like Apple pay, Airwallex and Noon might require some additional information, find specific details in the child attributes below. + pub connector_metadata: Option, + + /// Additional data that might be required by hyperswitch based on the requested features by the merchants. + pub feature_metadata: Option, + + /// Whether to generate the payment link for this payment or not (if applicable) + #[schema(value_type = EnablePaymentLinkRequest)] + #[serde(default)] + pub payment_link_enabled: common_enums::EnablePaymentLinkRequest, + + /// Configure a custom payment link for the particular payment + #[schema(value_type = Option)] + pub payment_link_config: Option, + + ///Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it. + #[schema(value_type = RequestIncrementalAuthorization)] + #[serde(default)] + pub request_incremental_authorization: common_enums::RequestIncrementalAuthorization, + + ///Will be used to expire client secret after certain amount of time to be supplied in seconds + ///(900) for 15 mins + #[schema(example = 900)] + pub session_expiry: Option, + + /// Additional data related to some frm(Fraud Risk Management) connectors + #[schema(value_type = Option, example = r#"{ "coverage_request" : "fraud", "fulfillment_method" : "delivery" }"#)] + pub frm_metadata: Option, + + /// Whether to perform external authentication (if applicable) + #[schema(value_type = External3dsAuthenticationRequest)] + #[serde(default)] + pub request_external_three_ds_authentication: common_enums::External3dsAuthenticationRequest, +} + +#[cfg(feature = "v2")] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct AmountDetails { + /// The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies) + #[schema(value_type = u64, example = 6540)] + #[serde(default, deserialize_with = "amount::deserialize")] + order_amount: Amount, + /// The currency of the order + #[schema(example = "USD", value_type = Currency)] + currency: common_enums::Currency, + /// The shipping cost of the order. This has to be collected from the merchant + shipping_cost: Option, + /// Tax details related to the order. This will be calculated by the external tax provider + tax_details: Option, + /// The action to whether calculate tax by calling external tax provider or not + #[serde(default)] + #[schema(value_type = TaxCalculationOverride)] + skip_external_tax_calculation: common_enums::TaxCalculationOverride, + /// The action to whether calculate surcharge or not + #[serde(default)] + #[schema(value_type = SurchargeCalculationOverride)] + skip_surcharge_calculation: common_enums::SurchargeCalculationOverride, + /// The surcharge amount to be added to the order, collected from the merchant + surcharge_amount: Option, + /// tax on surcharge amount + tax_on_surcharge: Option, +} + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct TaxDetails { + /// This is the tax related information that is calculated irrespective of any payment method. + /// This is calculated when the order is created with shipping details + pub default: Option, + + /// This is the tax related information that is calculated based on the payment method + /// This is calculated when calling the /calculate_tax API + pub payment_method_type: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PaymentMethodTypeTax { + /// The order tax amount for the payment method type + pub order_tax_amount: MinorUnit, + /// The payment method type + #[schema(value_type = PaymentMethodType, example = "google_pay")] + pub pmt: common_enums::PaymentMethodType, +} + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct DefaultTax { + /// The order tax amount for the default tax + pub order_tax_amount: MinorUnit, +} + #[derive( Default, Debug, diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index b5f26945e9..a9ece7e9c0 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1916,6 +1916,7 @@ pub enum CountryAlpha2 { serde::Serialize, strum::Display, strum::EnumString, + ToSchema, )] #[router_derive::diesel_enum(storage_type = "db_enum")] #[serde(rename_all = "snake_case")] @@ -3219,37 +3220,58 @@ pub enum DeleteStatus { } /// Whether 3ds authentication is requested or not -#[derive(Clone, Debug, PartialEq, serde::Serialize)] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, Default, ToSchema)] pub enum External3dsAuthenticationRequest { /// Request for 3ds authentication Enable, /// Skip 3ds authentication + #[default] Skip, } /// Whether payment link is requested to be enabled or not for this transaction -#[derive(Clone, Debug, PartialEq, serde::Serialize)] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, Default, ToSchema)] pub enum EnablePaymentLinkRequest { /// Request for enabling payment link Enable, /// Skip enabling payment link + #[default] Skip, } -/// Whether mit exemption is requested or not -#[derive(Clone, Debug, PartialEq, serde::Serialize)] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, Default, ToSchema)] pub enum MitExemptionRequest { /// Request for applying MIT exemption Apply, /// Skip applying MIT exemption + #[default] Skip, } -/// Whether customer is present / absent during the payment -#[derive(Clone, Debug, PartialEq, serde::Serialize)] +/// Set to true to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be false when merchant's doing merchant initiated payments and customer is not present while doing the payment. +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, Default, ToSchema)] pub enum PresenceOfCustomerDuringPayment { /// Customer is present during the payment. This is the default value + #[default] Present, /// Customer is absent during the payment Absent, } + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, Default, ToSchema)] +pub enum TaxCalculationOverride { + /// Skip calling the external tax provider + #[default] + Skip, + /// Calculate tax by calling the external tax provider + Calculate, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, Default, ToSchema)] +pub enum SurchargeCalculationOverride { + /// Skip calculating surcharge + #[default] + Skip, + /// Calculate surcharge + Calculate, +} diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index ce9a3b2cae..00ffb614bb 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -151,6 +151,6 @@ pub const ROLE_ID_INTERNAL_ADMIN: &str = "internal_admin"; pub const MAX_DESCRIPTION_LENGTH: u16 = 255; /// Max length allowed for Statement Descriptor -pub const MAX_STATEMENT_DESCRIPTOR_LENGTH: u16 = 255; +pub const MAX_STATEMENT_DESCRIPTOR_LENGTH: u16 = 22; /// Payout flow identifier used for performing GSM operations pub const PAYOUT_FLOW_STR: &str = "payout_flow"; diff --git a/crates/common_utils/src/id_type.rs b/crates/common_utils/src/id_type.rs index 26d2c0cdf6..78e3841690 100644 --- a/crates/common_utils/src/id_type.rs +++ b/crates/common_utils/src/id_type.rs @@ -27,7 +27,7 @@ pub use global_id::{payment::GlobalPaymentId, payment_methods::GlobalPaymentMeth pub use merchant::MerchantId; pub use merchant_connector_account::MerchantConnectorAccountId; pub use organization::OrganizationId; -pub use payment::PaymentId; +pub use payment::{PaymentId, PaymentReferenceId}; pub use profile::ProfileId; pub use routing::RoutingId; use serde::{Deserialize, Serialize}; diff --git a/crates/common_utils/src/id_type/payment.rs b/crates/common_utils/src/id_type/payment.rs index c919076e9c..d82a697b08 100644 --- a/crates/common_utils/src/id_type/payment.rs +++ b/crates/common_utils/src/id_type/payment.rs @@ -68,6 +68,13 @@ impl PaymentId { } } +crate::id_type!(PaymentReferenceId, "A type for payment_reference_id"); +crate::impl_id_type_methods!(PaymentReferenceId, "payment_reference_id"); + +// This is to display the `PaymentReferenceId` as PaymentReferenceId(abcd) +crate::impl_debug_id_type!(PaymentReferenceId); +crate::impl_try_from_cow_str_id_type!(PaymentReferenceId, "payment_reference_id"); + #[cfg(feature = "metrics")] /// This is implemented so that we can use payment id directly as attribute in metrics impl From for router_env::opentelemetry::Value { diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 9906f3c911..0cad88bfd4 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1026,7 +1026,8 @@ impl<'de, const MAX_LENGTH: u16, const MIN_LENGTH: u8> Deserialize<'de> } } -impl FromSql for LengthString +impl FromSql + for LengthString where DB: Backend, String: FromSql, @@ -1048,7 +1049,8 @@ where } } -impl Queryable for LengthString +impl Queryable + for LengthString where DB: Backend, Self: FromSql, @@ -1124,10 +1126,10 @@ where impl FromSql for StatementDescriptor where DB: Backend, - LengthString: FromSql, + LengthString: FromSql, { fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result { - let val = LengthString::::from_sql(bytes)?; + let val = LengthString::::from_sql(bytes)?; Ok(Self(val)) } } @@ -1135,7 +1137,7 @@ where impl ToSql for StatementDescriptor where DB: Backend, - LengthString: ToSql, + LengthString: ToSql, { fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { self.0.to_sql(out) diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 05fded520f..6e6e2f6f87 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -116,6 +116,9 @@ Never share your secret api keys. Keep them guarded and secure. routes::customers::customers_update, routes::customers::customers_delete, routes::customers::customers_list, + + //Routes for payments + routes::payments::payments_create_intent, ), components(schemas( common_utils::types::MinorUnit, @@ -304,6 +307,12 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentsCaptureRequest, api_models::payments::PaymentsSessionRequest, api_models::payments::PaymentsSessionResponse, + api_models::payments::PaymentsCreateIntentRequest, + api_models::payments::PaymentsCreateIntentResponse, + api_models::payments::AmountDetails, + api_models::payments::TaxDetails, + api_models::payments::DefaultTax, + api_models::payments::PaymentMethodTypeTax, api_models::payments::SessionToken, api_models::payments::ApplePaySessionResponse, api_models::payments::ThirdPartySdkSessionResponse, @@ -440,6 +449,13 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::PayoutStatus, api_models::enums::PayoutType, api_models::enums::TransactionType, + api_models::enums::PresenceOfCustomerDuringPayment, + api_models::enums::MitExemptionRequest, + api_models::enums::EnablePaymentLinkRequest, + api_models::enums::RequestIncrementalAuthorization, + api_models::enums::External3dsAuthenticationRequest, + api_models::enums::TaxCalculationOverride, + api_models::enums::SurchargeCalculationOverride, api_models::payments::FrmMessage, api_models::webhooks::OutgoingWebhook, api_models::webhooks::OutgoingWebhookContent, diff --git a/crates/openapi/src/routes/payments.rs b/crates/openapi/src/routes/payments.rs index a3fe0cd941..4cf8ec7cad 100644 --- a/crates/openapi/src/routes/payments.rs +++ b/crates/openapi/src/routes/payments.rs @@ -563,3 +563,32 @@ pub fn payments_complete_authorize() {} )] pub fn payments_dynamic_tax_calculation() {} + +/// Payments - Create Intent +/// +/// **Creates a payment intent object when amount_details are passed.** +/// +/// You will require the 'API - Key' from the Hyperswitch dashboard to make the first call, and use the 'client secret' returned in this API along with your 'publishable key' to make subsequent API calls from your client. +#[utoipa::path( + post, + path = "/v2/payments/create-intent", + request_body( + content = PaymentsCreateIntentRequest, + examples( + ( + "Create a payment intent with minimal fields" = ( + value = json!({"amount_details": {"order_amount": 6540, "currency": "USD"}}) + ) + ), + ), + ), + responses( + (status = 200, description = "Payment created", body = PaymentsCreateIntentResponse), + (status = 400, description = "Missing Mandatory fields") + ), + tag = "Payments", + operation_id = "Create a Payment Intent", + security(("api_key" = [])), +)] +#[cfg(feature = "v2")] +pub fn payments_create_intent() {}