diff --git a/openapi.json b/openapi.json index 7b95b9e..a08e3f0 100644 --- a/openapi.json +++ b/openapi.json @@ -103,6 +103,15 @@ "$ref": "#/components/schemas/Merchant" } ] + }, + { + "name": "Tokens", + "description": "Merchant tokens let your application accept card-present payments with SumUp SDKs that support token-based authentication. Use them when you want users to sign in to your application with your own authentication, then accept payments for a SumUp merchant account.\n\nCreate tokens on your backend using one of the [supported authentication methods](https://developer.sumup.com/api/authentication). Keep your authentication credentials on your backend. Return only the short-lived merchant token to your application and pass its `access_token` to the SDK.\n\nBefore returning a token, authenticate the user in your application and check that they can accept payments for the requested merchant account. A merchant token is limited to that account and the requested actions, and does not grant permissions beyond those of the identity that created it.\n\nTokens expire 15 minutes after creation. Use `expires_in` to determine the remaining lifetime and create a new token when needed. This endpoint does not return a refresh token. Treat merchant tokens as secrets: send them over HTTPS and keep them out of URLs, logs, and source code.", + "x-core-objects": [ + { + "$ref": "#/components/schemas/Token" + } + ] } ], "paths": { @@ -1602,29 +1611,7 @@ "$ref": "#/components/schemas/ErrorExtended" }, { - "type": "object", - "required": [ - "instance", - "error_code", - "error_message" - ], - "properties": { - "instance": { - "type": "string", - "description": "Unique identifier of this error occurrence.", - "example": "32a44c6c-85d3-49e8-86bf-a5bba98c4621" - }, - "error_code": { - "type": "string", - "description": "Platform code for the error.", - "example": "INVALID" - }, - "error_message": { - "type": "string", - "description": "Short description of the error.", - "example": "customer_id" - } - } + "$ref": "#/components/schemas/CustomerValidationError" } ] }, @@ -5573,7 +5560,7 @@ } } }, - "description": "Creates a Checkout for a Reader.\n\nThis process is asynchronous and the actual transaction may take some time to be started on the device.\n\n\nThere are some caveats when using this endpoint:\n* The target device must be online, otherwise checkout won't be accepted\n* After the checkout is accepted, the system has 60 seconds to start the payment on the target device. During this time, any other checkout for the same device will be rejected.\n\n\n**Note**: If the target device is a Solo, it must be in version 3.3.24.3 or higher.\n", + "description": "Creates a Checkout for a Reader.\n\nThis process is asynchronous and the actual transaction may take some time to be started on the device.\n\n\nThere are some caveats when using this endpoint:\n* The target device must be online, otherwise checkout won't be accepted\n* After the checkout is accepted, the system has 60 seconds to start the payment on the target device. During this time, any other checkout for the same device will be rejected.\n\n\n**Note**: If the target device is a Solo, it must be in version 3.3.24.3 or higher.\n\n\nOptionally include an `affiliate` object to attach integrator metadata to the payment.\nProvide both `app_id` and `key` when including this object.\n", "operationId": "CreateReaderCheckout", "parameters": [ { @@ -5622,16 +5609,22 @@ "400": { "content": { "application/json": { + "example": { + "errors": { + "detail": "Invalid affiliate key.", + "type": "INVALID_AFFILIATE_KEY" + } + }, "schema": { "$ref": "#/components/schemas/CreateReaderCheckoutError" } }, "application/problem+json": { "example": { - "detail": "Bad Request", + "detail": "Invalid affiliate key.", "status": 400, - "title": "Bad Request", - "type": "https://developer.sumup.com/problem/bad-request" + "title": "Invalid Affiliate Key", + "type": "https://developer.sumup.com/problem/invalid-affiliate-key" }, "schema": { "$ref": "#/components/schemas/Problem" @@ -5690,11 +5683,23 @@ } }, "application/problem+json": { - "example": { - "detail": "Validation failed", - "status": 422, - "title": "Unprocessable Entity", - "type": "https://developer.sumup.com/problem/validation-error" + "examples": { + "PaymentMethodNotAllowed": { + "value": { + "detail": "Payment method not allowed for this merchant.", + "status": 422, + "title": "Payment Method Not Allowed", + "type": "https://developer.sumup.com/problem/payment-method-not-allowed" + } + }, + "ValidationError": { + "value": { + "detail": "Validation failed", + "status": 422, + "title": "Unprocessable Content", + "type": "https://developer.sumup.com/problem/validation-error" + } + } }, "schema": { "$ref": "#/components/schemas/Problem" @@ -5856,14 +5861,14 @@ ] } }, - "/v0.1/merchants/{merchant_code}/readers/{reader_id}/terminate": { - "post": { + "/v0.1/merchants/{merchant_code}/readers/{reader_id}/settings": { + "get": { "callbacks": {}, - "description": "Terminate a Reader Checkout stops the current transaction on the target device.\n\nThis process is asynchronous and the actual termination may take some time to be performed on the device.\n\n\nThere are some caveats when using this endpoint:\n* The target device must be online, otherwise terminate won't be accepted\n* The action will succeed only if the device is waiting for cardholder action: e.g: waiting for card, waiting for PIN, etc.\n* There is no confirmation of the termination.\n\nIf a transaction is successfully terminated and `return_url` was provided on Checkout, the transaction status will be sent as `failed` to the provided URL.\n\n\n**Note**: If the target device is a Solo, it must be in version 3.3.28.0 or higher.\n", - "operationId": "CreateReaderTerminate", + "description": "Returns the menu lock settings for a Solo reader.\n\nFor an online reader, returns the current settings. For an offline reader,\nreturns the last saved settings, which may differ from its current configuration.\nReturns `404` if the reader is offline and no saved settings are available.\n\nThe response may include the menu lock PIN.\n", + "operationId": "GetReaderSettings", "parameters": [ { - "description": "Merchant Code", + "description": "The merchant code of the account that owns the reader.", "example": "MC0X0ABC", "in": "path", "name": "merchant_code", @@ -5873,7 +5878,132 @@ } }, { - "description": "The unique identifier of the Reader", + "description": "The unique identifier of the reader.", + "example": "rdr_3MSAFM23CK82VSTT4BN6RWSQ65", + "in": "path", + "name": "reader_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetReaderSettingsResponse" + } + } + }, + "description": "Reader settings retrieved successfully." + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateReaderSettingsError" + } + }, + "application/problem+json": { + "example": { + "detail": "Unauthorized", + "status": 401, + "title": "Unauthorized", + "type": "https://developer.sumup.com/problem/unauthorized" + }, + "schema": { + "$ref": "#/components/schemas/Problem" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFound" + } + }, + "application/problem+json": { + "example": { + "detail": "The requested resource doesn't exist or does not belong to you.", + "status": 404, + "title": "Requested resource couldn't be found.", + "type": "https://developer.sumup.com/problem/not-found" + }, + "schema": { + "$ref": "#/components/schemas/Problem" + } + } + }, + "description": "The reader was not found, or it is offline and has no saved settings." + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateReaderSettingsUnprocessableEntity" + } + }, + "application/problem+json": { + "example": { + "detail": "Reader settings are only supported for Solo readers.", + "status": 422, + "title": "Unsupported Device Model", + "type": "https://developer.sumup.com/problem/unsupported-device-model" + }, + "schema": { + "$ref": "#/components/schemas/Problem" + } + } + }, + "description": "The reader model is not supported, or the reader could not return its settings." + } + }, + "security": [ + { + "apiKey": [] + }, + { + "oauth2": [ + "readers.read" + ] + } + ], + "summary": "Get Reader Settings", + "tags": [ + "Readers" + ], + "x-codegen": { + "method_name": "get_reader_settings" + }, + "x-permissions": [ + "readers.checkouts.view" + ], + "x-scopes": [ + "readers.read" + ] + }, + "patch": { + "callbacks": {}, + "description": "Updates the menu lock settings for a Solo reader. The reader must be online.\nA successful response confirms that the reader applied the update.\n\nInclude at least one of `menu_lock.enabled` or `menu_lock.passcode`.\nOmitted settings keep their current values. The response contains only the\nsettings included in the request.\n\nWhen enabling menu lock for a reader without a PIN, include a four-digit PIN\nin `menu_lock.passcode` in the same request.\n", + "operationId": "UpdateReaderSettings", + "parameters": [ + { + "description": "The merchant code of the account that owns the reader.", + "example": "MC0X0ABC", + "in": "path", + "name": "merchant_code", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The unique identifier of the reader.", "example": "rdr_3MSAFM23CK82VSTT4BN6RWSQ65", "in": "path", "name": "reader_id", @@ -5885,23 +6015,31 @@ ], "requestBody": { "content": { - "application/json": {} + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateReaderSettingsRequest" + } + } }, - "description": "A checkout initial attributes", - "required": false + "description": "Menu lock settings to update.", + "required": true }, "responses": { - "202": { + "200": { "content": { - "application/json": {} + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateReaderSettingsResponse" + } + } }, - "description": "The Terminate action was successfully dispatched for the given reader." + "description": "Reader settings updated successfully." }, "400": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateReaderTerminateError" + "$ref": "#/components/schemas/UpdateReaderSettingsError" } }, "application/problem+json": { @@ -5916,13 +6054,13 @@ } } }, - "description": "Response when given params (or one of them) are invalid" + "description": "The request body is malformed." }, "401": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateReaderTerminateError" + "$ref": "#/components/schemas/UpdateReaderSettingsError" } }, "application/problem+json": { @@ -5958,13 +6096,19 @@ } } }, - "description": "Response when given reader is not found" + "description": "The reader was not found." }, "422": { "content": { "application/json": { + "example": { + "errors": { + "detail": "The device is offline.", + "type": "READER_OFFLINE" + } + }, "schema": { - "$ref": "#/components/schemas/CreateReaderTerminateUnprocessableEntity" + "$ref": "#/components/schemas/UpdateReaderSettingsUnprocessableEntity" } }, "application/problem+json": { @@ -5979,7 +6123,7 @@ } } }, - "description": "Response when given params (or one of them) are invalid" + "description": "The settings are invalid, the reader is offline, the reader model is not supported, or the reader could not apply the update." } }, "security": [ @@ -5992,26 +6136,26 @@ ] } ], - "summary": "Terminate a Reader Checkout", + "summary": "Update Reader Settings", "tags": [ "Readers" ], "x-codegen": { - "method_name": "terminate_checkout" + "method_name": "update_reader_settings" }, "x-permissions": [ - "readers.checkouts.delete" + "readers.checkouts.create" ], "x-scopes": [ "readers.write" ] } }, - "/v0.1/merchants/{merchant_code}/readers/{reader_id}/checkout/{checkout_id}": { - "get": { + "/v0.1/merchants/{merchant_code}/readers/{reader_id}/terminate": { + "post": { "callbacks": {}, - "description": "Get a Checkout for a Reader.\n", - "operationId": "GetReaderCheckout", + "description": "Terminate a Reader Checkout stops the current transaction on the target device.\n\nThis process is asynchronous and the actual termination may take some time to be performed on the device.\n\n\nThere are some caveats when using this endpoint:\n* The target device must be online, otherwise terminate won't be accepted\n* The action will succeed only if the device is waiting for cardholder action: e.g: waiting for card, waiting for PIN, etc.\n* There is no confirmation of the termination.\n\nIf a transaction is successfully terminated and `return_url` was provided on Checkout, the transaction status will be sent as `failed` to the provided URL.\n\n\n**Note**: If the target device is a Solo, it must be in version 3.3.28.0 or higher.\n", + "operationId": "CreateReaderTerminate", "parameters": [ { "description": "Merchant Code", @@ -6032,34 +6176,48 @@ "schema": { "type": "string" } - }, - { - "description": "The unique identifier of the Checkout", - "example": "74ecff66-1655-43ed-8ce3-193f49fa602f", - "in": "path", - "name": "checkout_id", - "required": true, - "schema": { - "type": "string" - } } ], + "requestBody": { + "content": { + "application/json": {} + }, + "description": "A checkout initial attributes", + "required": false + }, "responses": { - "200": { + "202": { + "content": { + "application/json": {} + }, + "description": "The Terminate action was successfully dispatched for the given reader." + }, + "400": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetReaderCheckoutResponse" + "$ref": "#/components/schemas/CreateReaderTerminateError" + } + }, + "application/problem+json": { + "example": { + "detail": "Bad Request", + "status": 400, + "title": "Bad Request", + "type": "https://developer.sumup.com/problem/bad-request" + }, + "schema": { + "$ref": "#/components/schemas/Problem" } } }, - "description": "The Checkout got successfully retrieved for the given reader." + "description": "Response when given params (or one of them) are invalid" }, "401": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateReaderCheckoutError" + "$ref": "#/components/schemas/CreateReaderTerminateError" } }, "application/problem+json": { @@ -6095,7 +6253,28 @@ } } }, - "description": "Response when given reader or checkout is not found" + "description": "Response when given reader is not found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateReaderTerminateUnprocessableEntity" + } + }, + "application/problem+json": { + "example": { + "detail": "The device is offline.", + "status": 422, + "title": "Reader Offline", + "type": "https://developer.sumup.com/problem/reader-offline" + }, + "schema": { + "$ref": "#/components/schemas/Problem" + } + } + }, + "description": "Response when given params (or one of them) are invalid" } }, "security": [ @@ -6104,7 +6283,123 @@ }, { "oauth2": [ - "readers.read" + "readers.write" + ] + } + ], + "summary": "Terminate a Reader Checkout", + "tags": [ + "Readers" + ], + "x-codegen": { + "method_name": "terminate_checkout" + }, + "x-permissions": [ + "readers.checkouts.delete" + ], + "x-scopes": [ + "readers.write" + ] + } + }, + "/v0.1/merchants/{merchant_code}/readers/{reader_id}/checkout/{checkout_id}": { + "get": { + "callbacks": {}, + "description": "Get a Checkout for a Reader.\n", + "operationId": "GetReaderCheckout", + "parameters": [ + { + "description": "Merchant Code", + "example": "MC0X0ABC", + "in": "path", + "name": "merchant_code", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The unique identifier of the Reader", + "example": "rdr_3MSAFM23CK82VSTT4BN6RWSQ65", + "in": "path", + "name": "reader_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The unique identifier of the Checkout", + "example": "74ecff66-1655-43ed-8ce3-193f49fa602f", + "in": "path", + "name": "checkout_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetReaderCheckoutResponse" + } + } + }, + "description": "The Checkout got successfully retrieved for the given reader." + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateReaderCheckoutError" + } + }, + "application/problem+json": { + "example": { + "detail": "Unauthorized", + "status": 401, + "title": "Unauthorized", + "type": "https://developer.sumup.com/problem/unauthorized" + }, + "schema": { + "$ref": "#/components/schemas/Problem" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFound" + } + }, + "application/problem+json": { + "example": { + "detail": "The requested resource doesn't exist or does not belong to you.", + "status": 404, + "title": "Requested resource couldn't be found.", + "type": "https://developer.sumup.com/problem/not-found" + }, + "schema": { + "$ref": "#/components/schemas/Problem" + } + } + }, + "description": "Response when given reader or checkout is not found" + } + }, + "security": [ + { + "apiKey": [] + }, + { + "oauth2": [ + "readers.read" ] } ], @@ -6122,6 +6417,157 @@ "readers.read" ] } + }, + "/v0.1/merchants/{merchant_code}/tokens": { + "post": { + "summary": "Create a merchant token", + "description": "Creates a short-lived token for the merchant account identified by `merchant_code` and the requested actions.\n\nCall this endpoint from your backend using a [supported authentication method](https://developer.sumup.com/api/authentication). You must have access to the merchant account. Before returning the token, check that the user signed in to your application is allowed to accept payments for that account.\n\nPass the returned `access_token` to the SDK. The token expires 15 minutes after creation; use `expires_in` for its remaining lifetime. To continue after it expires, create a new token through this endpoint.", + "operationId": "CreateMerchantToken", + "tags": [ + "Tokens" + ], + "security": [ + { + "apiKey": [] + }, + { + "oauth2": [] + } + ], + "x-scopes": [], + "x-codegen": { + "method_name": "create" + }, + "x-permissions": [ + { + "relation": "tokens.create", + "object_type": "merchant", + "object_id_param": "merchant_code" + } + ], + "parameters": [ + { + "in": "path", + "name": "merchant_code", + "description": "Unique code of the merchant account that will receive the payments.", + "required": true, + "schema": { + "type": "string", + "example": "MC0X0ABC" + } + } + ], + "requestBody": { + "description": "Actions the merchant token should allow.", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "actions" + ], + "properties": { + "actions": { + "type": "array", + "description": "Actions the token allows for this merchant account.", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "checkout" + ] + }, + "example": [ + "checkout" + ] + } + } + }, + "example": { + "actions": [ + "checkout" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Merchant token created. Pass its access_token to the SDK.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Token" + }, + "example": { + "access_token": "MERCHANT_TOKEN", + "token_type": "Bearer", + "expires_in": 899 + } + } + } + }, + "400": { + "description": "The request body is invalid or contains unsupported or duplicate actions.", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/Problem" + }, + "example": { + "type": "https://developer.sumup.com/problem/bad-request", + "title": "Bad Request", + "status": 400, + "detail": "The request contains an unsupported action." + } + } + } + }, + "401": { + "description": "Authentication is missing, invalid, or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Problem" + }, + "example": { + "type": "https://developer.sumup.com/problem/unauthorized", + "title": "Unauthorized", + "status": 401 + } + }, + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/Problem" + }, + "example": { + "type": "https://developer.sumup.com/problem/unauthorized", + "title": "Unauthorized", + "status": 401, + "detail": "Token is invalid or expired." + } + } + } + }, + "403": { + "description": "The authenticated identity does not have permission to create tokens for this merchant account.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Problem" + }, + "example": { + "type": "https://developer.sumup.com/problem/forbidden", + "title": "Forbidden", + "status": 403 + } + } + } + } + } + } } }, "components": { @@ -6768,6 +7214,33 @@ } } }, + "CustomerValidationError": { + "title": "Customer Validation Error", + "description": "Details of a customer validation error.", + "type": "object", + "required": [ + "instance", + "error_code", + "error_message" + ], + "properties": { + "instance": { + "type": "string", + "description": "Unique identifier of this error occurrence.", + "example": "32a44c6c-85d3-49e8-86bf-a5bba98c4621" + }, + "error_code": { + "type": "string", + "description": "Platform code for the error.", + "example": "INVALID" + }, + "error_message": { + "type": "string", + "description": "Short description of the error.", + "example": "customer_id" + } + } + }, "Error": { "title": "Error", "type": "object", @@ -9783,6 +10256,32 @@ "minLength": 8, "maxLength": 9 }, + "UpdateReaderSettingsError": { + "description": "Details of a failed reader settings request.", + "properties": { + "errors": { + "properties": { + "detail": { + "description": "Error message", + "type": "string" + }, + "type": { + "description": "Error code", + "type": "string" + } + }, + "required": [ + "detail" + ], + "type": "object" + } + }, + "required": [ + "errors" + ], + "title": "UpdateReaderSettingsError", + "type": "object" + }, "CreateReaderCheckoutUnprocessableEntity": { "description": "Unprocessable entity", "example": { @@ -9800,7 +10299,7 @@ "must be a valid URL" ], "tip_rates": [ - "must be between 0.01 and 0.99" + "has an invalid entry" ], "total_amount": [ "must be greater than 0" @@ -9818,6 +10317,15 @@ } } }, + "PaymentMethodNotAllowed": { + "description": "Error returned when the requested payment method is not supported for the merchant (e.g. pix for non-BR merchants).", + "value": { + "errors": { + "detail": "Payment method not allowed for this merchant.", + "type": "PAYMENT_METHOD_NOT_ALLOWED" + } + } + }, "ReaderBusy": { "description": "Error returned when a checkout was requested in the last 60 seconds.", "value": { @@ -9883,6 +10391,7 @@ "client_transaction_id": "00e33a36-c99b-4cb2-b635-b90c1455c9c8", "created_at": "2026-07-07T20:41:16.315434Z", "installments": 1, + "payment_failure_reason": null, "payment_status": "pending", "payment_type": "card", "reader_firmware_version": "3.3.3.21", @@ -9901,10 +10410,11 @@ "data": { "properties": { "card_type": { - "description": "Type of the card. Required for some countries", + "description": "Type of the card, or null when no card type was specified.", "enum": [ "credit", - "debit" + "debit", + null ], "type": [ "string", @@ -9933,14 +10443,14 @@ ] }, "payment_failure_reason": { - "description": "Payment failure reason", + "description": "Reason for the payment failure, or null when no failure reason is available.", "type": [ "string", "null" ] }, "payment_status": { - "description": "Payment status from payments v2 event", + "description": "Status of the payment, or null when no payment status is available.", "type": [ "string", "null" @@ -10029,6 +10539,7 @@ "reader_firmware_version", "installments", "payment_status", + "payment_failure_reason", "valid_until", "created_at", "updated_at", @@ -10044,6 +10555,70 @@ "title": "GetReaderCheckoutResponse", "type": "object" }, + "GetReaderSettingsResponse": { + "description": "Menu lock settings reported by the reader, or the last saved settings when offline.\n", + "example": { + "data": { + "menu_lock": { + "enabled": true, + "passcode": "1234" + } + } + }, + "properties": { + "data": { + "properties": { + "menu_lock": { + "description": "Menu lock configuration. Fields may be absent if no value is available.", + "properties": { + "enabled": { + "description": "Whether menu lock is enabled.", + "example": true, + "type": "boolean" + }, + "passcode": { + "description": "Four-digit PIN used to unlock the reader's menu.", + "example": "1234", + "format": "password", + "pattern": "^[0-9]{4}$", + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "menu_lock" + ], + "type": "object" + } + }, + "required": [ + "data" + ], + "title": "GetReaderSettingsResponse", + "type": "object" + }, + "UpdateReaderSettingsUnprocessableEntity": { + "description": "The reader cannot complete the settings request, or the settings are invalid.", + "example": { + "errors": { + "detail": "Reader settings are only supported for Solo readers.", + "type": "UNSUPPORTED_DEVICE_MODEL" + } + }, + "properties": { + "errors": { + "additionalProperties": true, + "type": "object" + } + }, + "required": [ + "errors" + ], + "title": "UpdateReaderSettingsUnprocessableEntity", + "type": "object" + }, "StatusResponse": { "description": "Status of a device", "example": { @@ -10202,6 +10777,8 @@ "type": { "description": "Key indicating type of error", "enum": [ + "INVALID_AFFILIATE_KEY", + "APP_OUTDATED", "INVALID_BEARER_TOKEN", "INVALID_USER_AGENT", "NOT_ENOUGH_UNPAID_PAYOUTS", @@ -10238,7 +10815,7 @@ "type": "string" }, "client_transaction_id": { - "description": "The client transaction ID is a unique identifier for the transaction that is generated for the client.\n\nIt can be used later to fetch the transaction details via the [Transactions API](https://developer.sumup.com/api/transactions/get).\n", + "description": "Unique identifier for the transaction associated with this checkout.\nUse this value to match the checkout with payment events and transaction records.\n", "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "type": "string" } @@ -10255,6 +10832,95 @@ "title": "CreateReaderCheckoutResponse", "type": "object" }, + "UpdateReaderSettingsRequest": { + "description": "Menu lock settings to update for a Solo reader.", + "example": { + "menu_lock": { + "enabled": true, + "passcode": "1234" + } + }, + "properties": { + "menu_lock": { + "description": "Menu lock configuration. Provide at least one of `enabled` or `passcode`.", + "minProperties": 1, + "properties": { + "enabled": { + "description": "Whether menu lock is enabled.", + "example": true, + "type": "boolean" + }, + "passcode": { + "description": "Four-digit PIN used to unlock the reader's menu.", + "example": "1234", + "format": "password", + "pattern": "^[0-9]{4}$", + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "menu_lock" + ], + "title": "UpdateReaderSettingsRequest", + "type": "object" + }, + "UpdateReaderSettingsResponse": { + "description": "Menu lock settings applied to the reader.", + "example": { + "data": { + "menu_lock": { + "enabled": true, + "passcode": "1234" + }, + "status": "applied" + } + }, + "properties": { + "data": { + "properties": { + "menu_lock": { + "description": "Settings included in the update. Omitted fields are not returned.", + "properties": { + "enabled": { + "description": "Whether menu lock is enabled.", + "example": true, + "type": "boolean" + }, + "passcode": { + "description": "Four-digit PIN used to unlock the reader's menu.", + "example": "1234", + "format": "password", + "pattern": "^[0-9]{4}$", + "type": "string" + } + }, + "type": "object" + }, + "status": { + "description": "Indicates that the reader applied the settings update.", + "enum": [ + "applied" + ], + "example": "applied", + "type": "string" + } + }, + "required": [ + "status", + "menu_lock" + ], + "type": "object" + } + }, + "required": [ + "data" + ], + "title": "UpdateReaderSettingsResponse", + "type": "object" + }, "Unauthorized": { "description": "401 Unauthorized", "example": { @@ -10291,7 +10957,7 @@ "type": "object" }, "CreateReaderCheckoutRequest": { - "description": "Reader Checkout", + "description": "Payment details for a Reader Checkout.\n", "example": { "aade": { "provider_id": "123", @@ -10302,7 +10968,10 @@ "app_id": "com.example.app", "foreign_transaction_id": "123456", "key": "ef7b684a-d6f4-4e93-9b1b-6acdd6564a8e", - "tags": {} + "tags": { + "custom_key_1": "custom_value_1", + "custom_key_2": "custom_value_2" + } }, "card_type": "debit", "description": "This is a description...", @@ -10348,26 +11017,26 @@ "type": "object" }, "affiliate": { - "description": "Affiliate metadata for the transaction.\nIt is a field that allow for integrators to track the source of the transaction.\n", + "description": "Optional affiliate metadata associated with the checkout's payment.\nProvide both `app_id` and `key` when including this object.\n", "properties": { "app_id": { - "description": "Application ID of the affiliate.\nIt is a unique identifier for the application and should be set by the integrator in the [Affiliate Keys](https://developer.sumup.com/affiliate-keys) page.\n", + "description": "Integrator application identifier from the [Affiliate Keys](https://developer.sumup.com/affiliate-keys) page.\nRequired when the affiliate object is provided.\n", "example": "com.example.app", "type": "string" }, "foreign_transaction_id": { - "description": "Foreign transaction ID of the affiliate.\nIt is a unique identifier for the transaction.\nIt can be used later to fetch the transaction details via the [Transactions API](https://developer.sumup.com/api/transactions/get).\n", + "description": "Integrator-owned transaction reference. Optional.\nCan be used to retrieve the transaction via the [Transactions API](https://developer.sumup.com/api/transactions/get).\n", "example": "19e12390-72cf-4f9f-80b5-b0c8a67fa43f", "type": "string" }, "key": { - "description": "Key of the affiliate.\nIt is a unique identifier for the key and should be generated by the integrator in the [Affiliate Keys](https://developer.sumup.com/affiliate-keys) page.\n", + "description": "Affiliate key generated in the [Affiliate Keys](https://developer.sumup.com/affiliate-keys) page.\nRequired when the affiliate object is provided.\n", "example": "123e4567-e89b-12d3-a456-426614174000", "type": "string" }, "tags": { "additionalProperties": true, - "description": "Additional metadata for the transaction.\nIt is key-value object that can be associated with the transaction.\n", + "description": "Optional key-value metadata associated with the transaction.\n", "example": { "custom_key_1": "custom_value_1", "custom_key_2": "custom_value_2" @@ -10377,8 +11046,7 @@ }, "required": [ "app_id", - "key", - "foreign_transaction_id" + "key" ], "title": "Affiliate", "type": [ @@ -10387,7 +11055,7 @@ ] }, "card_type": { - "description": "The card type of the card used for the transaction.\nIs is required only for some countries (e.g: Brazil).\n", + "description": "The card type of the card used for the transaction.\nIt is required only for some countries (e.g: Brazil).\n", "enum": [ "credit", "debit" @@ -10400,7 +11068,7 @@ "type": "string" }, "installments": { - "description": "Number of installments for the transaction.\nIt may vary according to the merchant country.\nFor example, in Brazil, the maximum number of installments is 12.\n\nOmit if the merchant country does support installments.\nOtherwise, the checkout will be rejected.\n", + "description": "Number of installments for the transaction.\nIt may vary according to the merchant country.\nFor example, in Brazil, the maximum number of installments is 12.\n\nOmit if the merchant country does not support installments.\nOtherwise, the checkout will be rejected.\n", "example": 1, "minimum": 1, "type": [ @@ -10408,6 +11076,16 @@ "null" ] }, + "payment_type": { + "default": "card", + "description": "The payment method type for the transaction. Defaults to `card`.\n\nUse `pix` to initiate a Pix QR-code payment flow on the device.\nPix is only supported for Brazilian merchants; other merchants will receive a 422 error.\n", + "enum": [ + "card", + "pix" + ], + "example": "card", + "type": "string" + }, "return_url": { "description": "Webhook URL to which the payment result will be sent.\nIt must be a HTTPS url.\n", "example": "https://www.example.com", @@ -10415,13 +11093,18 @@ "type": "string" }, "tip_rates": { - "description": "List of tipping rates to be displayed to the cardholder.\nThe rates are in percentage and should be between 0.01 and 0.99.\nThe list should be sorted in ascending order.\n", + "description": "Exactly three distinct tipping rates to be displayed to the cardholder.\nEach rate is a fraction between 0.01 and 1.00 in increments of 0.01.\nThe rates are sorted in ascending order by the server.\n", "items": { "format": "float", + "maximum": 1, + "minimum": 0.01, "multipleOf": 0.01, "type": "number" }, - "type": "array" + "maxItems": 3, + "minItems": 3, + "type": "array", + "uniqueItems": true }, "tip_timeout": { "default": 30, @@ -10566,6 +11249,36 @@ ], "title": "NotFound", "type": "object" + }, + "Token": { + "type": "object", + "description": "A short-lived credential for the requested merchant account and actions. Pass access_token to a SumUp SDK that supports merchant tokens.", + "required": [ + "access_token", + "token_type", + "expires_in" + ], + "properties": { + "access_token": { + "type": "string", + "description": "Secret token to pass to the SDK. Treat this value as an opaque string; do not parse it or depend on its format.", + "example": "MERCHANT_TOKEN" + }, + "token_type": { + "type": "string", + "description": "Authentication scheme used by the token. Always Bearer.", + "enum": [ + "Bearer" + ], + "example": "Bearer" + }, + "expires_in": { + "type": "integer", + "description": "Remaining lifetime of the token in seconds when the response is created. Tokens expire 15 minutes after creation. Request a new token when needed.", + "minimum": 0, + "example": 899 + } + } } }, "requestBodies": { diff --git a/src/SumUp/Models/BadRequestErrorsType.g.cs b/src/SumUp/Models/BadRequestErrorsType.g.cs index 5431237..890ad48 100644 --- a/src/SumUp/Models/BadRequestErrorsType.g.cs +++ b/src/SumUp/Models/BadRequestErrorsType.g.cs @@ -9,6 +9,10 @@ namespace SumUp; [JsonConverter(typeof(EnumMemberJsonConverterFactory))] public enum BadRequestErrorsType { + [EnumMember(Value = "INVALID_AFFILIATE_KEY")] + InvalidAffiliateKey, + [EnumMember(Value = "APP_OUTDATED")] + AppOutdated, [EnumMember(Value = "INVALID_BEARER_TOKEN")] InvalidBearerToken, [EnumMember(Value = "INVALID_USER_AGENT")] diff --git a/src/SumUp/Models/CreateReaderCheckoutRequest.g.cs b/src/SumUp/Models/CreateReaderCheckoutRequest.g.cs index 8e90e8b..4f4cd4c 100644 --- a/src/SumUp/Models/CreateReaderCheckoutRequest.g.cs +++ b/src/SumUp/Models/CreateReaderCheckoutRequest.g.cs @@ -5,28 +5,31 @@ namespace SumUp; using System.Text.Json.Serialization; using System.Collections.Generic; -/// Reader Checkout +/// Payment details for a Reader Checkout. public sealed partial class CreateReaderCheckoutRequest { /// Optional object containing data for transactions from ERP integrators in Greece that comply with the AADE 1155 protocol. When such regulatory/business requirements apply, this object must be provided and contains the data needed to validate the transaction with the AADE signature provider. [JsonPropertyName("aade")] public CreateReaderCheckoutRequestAade? Aade { get; set; } - /// Affiliate metadata for the transaction. It is a field that allow for integrators to track the source of the transaction. + /// Optional affiliate metadata associated with the checkout's payment. Provide both app_id and key when including this object. [JsonPropertyName("affiliate")] public CreateReaderCheckoutRequestAffiliate? Affiliate { get; set; } - /// The card type of the card used for the transaction. Is is required only for some countries (e.g: Brazil). + /// The card type of the card used for the transaction. It is required only for some countries (e.g: Brazil). [JsonPropertyName("card_type")] public CreateReaderCheckoutRequestCardType? CardType { get; set; } /// Description of the checkout to be shown in the Merchant Sales [JsonPropertyName("description")] public string? Description { get; set; } - /// Number of installments for the transaction. It may vary according to the merchant country. For example, in Brazil, the maximum number of installments is 12. Omit if the merchant country does support installments. Otherwise, the checkout will be rejected. + /// Number of installments for the transaction. It may vary according to the merchant country. For example, in Brazil, the maximum number of installments is 12. Omit if the merchant country does not support installments. Otherwise, the checkout will be rejected. [JsonPropertyName("installments")] public int? Installments { get; set; } + /// The payment method type for the transaction. Defaults to card. Use pix to initiate a Pix QR-code payment flow on the device. Pix is only supported for Brazilian merchants; other merchants will receive a 422 error. + [JsonPropertyName("payment_type")] + public CreateReaderCheckoutRequestPaymentType? PaymentType { get; set; } /// Webhook URL to which the payment result will be sent. It must be a HTTPS url. [JsonPropertyName("return_url")] public string? ReturnUrl { get; set; } - /// List of tipping rates to be displayed to the cardholder. The rates are in percentage and should be between 0.01 and 0.99. The list should be sorted in ascending order. + /// Exactly three distinct tipping rates to be displayed to the cardholder. Each rate is a fraction between 0.01 and 1.00 in increments of 0.01. The rates are sorted in ascending order by the server. [JsonPropertyName("tip_rates")] public IEnumerable? TipRates { get; set; } /// Time in seconds the cardholder has to select a tip rate. If not provided, the default value is 30 seconds. It can only be set if tip_rates is provided. Note: If the target device is a Solo, it must be in version 3.3.38.0 or higher. diff --git a/src/SumUp/Models/CreateReaderCheckoutRequestAffiliate.g.cs b/src/SumUp/Models/CreateReaderCheckoutRequestAffiliate.g.cs index ca8487d..4e096cf 100644 --- a/src/SumUp/Models/CreateReaderCheckoutRequestAffiliate.g.cs +++ b/src/SumUp/Models/CreateReaderCheckoutRequestAffiliate.g.cs @@ -4,19 +4,19 @@ namespace SumUp; using System.Text.Json.Serialization; -/// Affiliate metadata for the transaction. It is a field that allow for integrators to track the source of the transaction. +/// Optional affiliate metadata associated with the checkout's payment. Provide both app_id and key when including this object. public sealed partial class CreateReaderCheckoutRequestAffiliate { - /// Application ID of the affiliate. It is a unique identifier for the application and should be set by the integrator in the Affiliate Keys page. + /// Integrator application identifier from the Affiliate Keys page. Required when the affiliate object is provided. [JsonPropertyName("app_id")] public string AppId { get; set; } = default!; - /// Foreign transaction ID of the affiliate. It is a unique identifier for the transaction. It can be used later to fetch the transaction details via the Transactions API. + /// Integrator-owned transaction reference. Optional. Can be used to retrieve the transaction via the Transactions API. [JsonPropertyName("foreign_transaction_id")] - public string ForeignTransactionId { get; set; } = default!; - /// Key of the affiliate. It is a unique identifier for the key and should be generated by the integrator in the Affiliate Keys page. + public string? ForeignTransactionId { get; set; } + /// Affiliate key generated in the Affiliate Keys page. Required when the affiliate object is provided. [JsonPropertyName("key")] public string Key { get; set; } = default!; - /// Additional metadata for the transaction. It is key-value object that can be associated with the transaction. + /// Optional key-value metadata associated with the transaction. [JsonPropertyName("tags")] public JsonObject? Tags { get; set; } } \ No newline at end of file diff --git a/src/SumUp/Models/CreateReaderCheckoutRequestPaymentType.g.cs b/src/SumUp/Models/CreateReaderCheckoutRequestPaymentType.g.cs new file mode 100644 index 0000000..626eb49 --- /dev/null +++ b/src/SumUp/Models/CreateReaderCheckoutRequestPaymentType.g.cs @@ -0,0 +1,16 @@ +// +#nullable enable + +namespace SumUp; + +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +[JsonConverter(typeof(EnumMemberJsonConverterFactory))] +public enum CreateReaderCheckoutRequestPaymentType +{ + [EnumMember(Value = "card")] + Card, + [EnumMember(Value = "pix")] + Pix, +} \ No newline at end of file diff --git a/src/SumUp/Models/CreateReaderCheckoutResponseData.g.cs b/src/SumUp/Models/CreateReaderCheckoutResponseData.g.cs index 1b5ad58..51a906d 100644 --- a/src/SumUp/Models/CreateReaderCheckoutResponseData.g.cs +++ b/src/SumUp/Models/CreateReaderCheckoutResponseData.g.cs @@ -9,7 +9,7 @@ public sealed partial class CreateReaderCheckoutResponseData /// The checkout ID is a unique identifier for the checkout. [JsonPropertyName("checkout_id")] public string? CheckoutId { get; set; } - /// The client transaction ID is a unique identifier for the transaction that is generated for the client. It can be used later to fetch the transaction details via the Transactions API. + /// Unique identifier for the transaction associated with this checkout. Use this value to match the checkout with payment events and transaction records. [JsonPropertyName("client_transaction_id")] public string ClientTransactionId { get; set; } = default!; } \ No newline at end of file diff --git a/src/SumUp/Models/CustomerValidationError.g.cs b/src/SumUp/Models/CustomerValidationError.g.cs new file mode 100644 index 0000000..34d98ed --- /dev/null +++ b/src/SumUp/Models/CustomerValidationError.g.cs @@ -0,0 +1,19 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Details of a customer validation error. +public sealed partial class CustomerValidationError +{ + /// Platform code for the error. + [JsonPropertyName("error_code")] + public string ErrorCode { get; set; } = default!; + /// Short description of the error. + [JsonPropertyName("error_message")] + public string ErrorMessage { get; set; } = default!; + /// Unique identifier of this error occurrence. + [JsonPropertyName("instance")] + public string Instance { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/Models/GetReaderCheckoutResponseData.g.cs b/src/SumUp/Models/GetReaderCheckoutResponseData.g.cs index e2cedf1..92edbaf 100644 --- a/src/SumUp/Models/GetReaderCheckoutResponseData.g.cs +++ b/src/SumUp/Models/GetReaderCheckoutResponseData.g.cs @@ -6,7 +6,7 @@ namespace SumUp; using System.Text.Json.Serialization; public sealed partial class GetReaderCheckoutResponseData { - /// Type of the card. Required for some countries + /// Type of the card, or null when no card type was specified. [JsonPropertyName("card_type")] public GetReaderCheckoutResponseDataCardType? CardType { get; set; } /// Unique identifier for the checkout @@ -21,10 +21,10 @@ public sealed partial class GetReaderCheckoutResponseData /// Number of installments for the transaction. Required for some countries. [JsonPropertyName("installments")] public int? Installments { get; set; } - /// Payment failure reason + /// Reason for the payment failure, or null when no failure reason is available. [JsonPropertyName("payment_failure_reason")] public string? PaymentFailureReason { get; set; } - /// Payment status from payments v2 event + /// Status of the payment, or null when no payment status is available. [JsonPropertyName("payment_status")] public string? PaymentStatus { get; set; } /// Type of the payment. Required for some countries diff --git a/src/SumUp/Models/GetReaderCheckoutResponseDataCardType.g.cs b/src/SumUp/Models/GetReaderCheckoutResponseDataCardType.g.cs index abfc0b2..7c59614 100644 --- a/src/SumUp/Models/GetReaderCheckoutResponseDataCardType.g.cs +++ b/src/SumUp/Models/GetReaderCheckoutResponseDataCardType.g.cs @@ -13,4 +13,6 @@ public enum GetReaderCheckoutResponseDataCardType Credit, [EnumMember(Value = "debit")] Debit, + [EnumMember(Value = "null")] + NullValue, } \ No newline at end of file diff --git a/src/SumUp/Models/GetReaderSettingsResponse.g.cs b/src/SumUp/Models/GetReaderSettingsResponse.g.cs new file mode 100644 index 0000000..a4433ea --- /dev/null +++ b/src/SumUp/Models/GetReaderSettingsResponse.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Menu lock settings reported by the reader, or the last saved settings when offline. +public sealed partial class GetReaderSettingsResponse +{ + [JsonPropertyName("data")] + public GetReaderSettingsResponseData Data { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/Models/GetReaderSettingsResponseData.g.cs b/src/SumUp/Models/GetReaderSettingsResponseData.g.cs new file mode 100644 index 0000000..702727d --- /dev/null +++ b/src/SumUp/Models/GetReaderSettingsResponseData.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +public sealed partial class GetReaderSettingsResponseData +{ + /// Menu lock configuration. Fields may be absent if no value is available. + [JsonPropertyName("menu_lock")] + public GetReaderSettingsResponseDataMenuLock MenuLock { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/Models/GetReaderSettingsResponseDataMenuLock.g.cs b/src/SumUp/Models/GetReaderSettingsResponseDataMenuLock.g.cs new file mode 100644 index 0000000..aff1699 --- /dev/null +++ b/src/SumUp/Models/GetReaderSettingsResponseDataMenuLock.g.cs @@ -0,0 +1,16 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Menu lock configuration. Fields may be absent if no value is available. +public sealed partial class GetReaderSettingsResponseDataMenuLock +{ + /// Whether menu lock is enabled. + [JsonPropertyName("enabled")] + public bool? Enabled { get; set; } + /// Four-digit PIN used to unlock the reader's menu. + [JsonPropertyName("passcode")] + public string? Passcode { get; set; } +} \ No newline at end of file diff --git a/src/SumUp/Models/Token.g.cs b/src/SumUp/Models/Token.g.cs new file mode 100644 index 0000000..4cadee7 --- /dev/null +++ b/src/SumUp/Models/Token.g.cs @@ -0,0 +1,19 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// A short-lived credential for the requested merchant account and actions. Pass access_token to a SumUp SDK that supports merchant tokens. +public sealed partial class Token +{ + /// Secret token to pass to the SDK. Treat this value as an opaque string; do not parse it or depend on its format. + [JsonPropertyName("access_token")] + public string AccessToken { get; set; } = default!; + /// Remaining lifetime of the token in seconds when the response is created. Tokens expire 15 minutes after creation. Request a new token when needed. + [JsonPropertyName("expires_in")] + public int ExpiresIn { get; set; } + /// Authentication scheme used by the token. Always Bearer. + [JsonPropertyName("token_type")] + public TokenTokenType TokenType { get; set; } +} \ No newline at end of file diff --git a/src/SumUp/Models/TokenTokenType.g.cs b/src/SumUp/Models/TokenTokenType.g.cs new file mode 100644 index 0000000..f08b5da --- /dev/null +++ b/src/SumUp/Models/TokenTokenType.g.cs @@ -0,0 +1,14 @@ +// +#nullable enable + +namespace SumUp; + +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +[JsonConverter(typeof(EnumMemberJsonConverterFactory))] +public enum TokenTokenType +{ + [EnumMember(Value = "Bearer")] + Bearer, +} \ No newline at end of file diff --git a/src/SumUp/Models/TokensCreateRequest.g.cs b/src/SumUp/Models/TokensCreateRequest.g.cs new file mode 100644 index 0000000..e2445c7 --- /dev/null +++ b/src/SumUp/Models/TokensCreateRequest.g.cs @@ -0,0 +1,13 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +using System.Collections.Generic; +public sealed partial class TokensCreateRequest +{ + /// Actions the token allows for this merchant account. + [JsonPropertyName("actions")] + public IEnumerable Actions { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/Models/TokensCreateRequestActionsItem.g.cs b/src/SumUp/Models/TokensCreateRequestActionsItem.g.cs new file mode 100644 index 0000000..04f4836 --- /dev/null +++ b/src/SumUp/Models/TokensCreateRequestActionsItem.g.cs @@ -0,0 +1,14 @@ +// +#nullable enable + +namespace SumUp; + +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +[JsonConverter(typeof(EnumMemberJsonConverterFactory))] +public enum TokensCreateRequestActionsItem +{ + [EnumMember(Value = "checkout")] + Checkout, +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsError.g.cs b/src/SumUp/Models/UpdateReaderSettingsError.g.cs new file mode 100644 index 0000000..9cc14af --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsError.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Details of a failed reader settings request. +public sealed partial class UpdateReaderSettingsError +{ + [JsonPropertyName("errors")] + public UpdateReaderSettingsErrorErrors Errors { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsErrorErrors.g.cs b/src/SumUp/Models/UpdateReaderSettingsErrorErrors.g.cs new file mode 100644 index 0000000..34153c5 --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsErrorErrors.g.cs @@ -0,0 +1,15 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +public sealed partial class UpdateReaderSettingsErrorErrors +{ + /// Error message + [JsonPropertyName("detail")] + public string Detail { get; set; } = default!; + /// Error code + [JsonPropertyName("type")] + public string? Type { get; set; } +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsRequest.g.cs b/src/SumUp/Models/UpdateReaderSettingsRequest.g.cs new file mode 100644 index 0000000..e611cd2 --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsRequest.g.cs @@ -0,0 +1,13 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Menu lock settings to update for a Solo reader. +public sealed partial class UpdateReaderSettingsRequest +{ + /// Menu lock configuration. Provide at least one of enabled or passcode. + [JsonPropertyName("menu_lock")] + public UpdateReaderSettingsRequestMenuLock MenuLock { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsRequestMenuLock.g.cs b/src/SumUp/Models/UpdateReaderSettingsRequestMenuLock.g.cs new file mode 100644 index 0000000..c5214d1 --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsRequestMenuLock.g.cs @@ -0,0 +1,16 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Menu lock configuration. Provide at least one of enabled or passcode. +public sealed partial class UpdateReaderSettingsRequestMenuLock +{ + /// Whether menu lock is enabled. + [JsonPropertyName("enabled")] + public bool? Enabled { get; set; } + /// Four-digit PIN used to unlock the reader's menu. + [JsonPropertyName("passcode")] + public string? Passcode { get; set; } +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsResponse.g.cs b/src/SumUp/Models/UpdateReaderSettingsResponse.g.cs new file mode 100644 index 0000000..1939506 --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsResponse.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Menu lock settings applied to the reader. +public sealed partial class UpdateReaderSettingsResponse +{ + [JsonPropertyName("data")] + public UpdateReaderSettingsResponseData Data { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsResponseData.g.cs b/src/SumUp/Models/UpdateReaderSettingsResponseData.g.cs new file mode 100644 index 0000000..f3d9713 --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsResponseData.g.cs @@ -0,0 +1,15 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +public sealed partial class UpdateReaderSettingsResponseData +{ + /// Settings included in the update. Omitted fields are not returned. + [JsonPropertyName("menu_lock")] + public UpdateReaderSettingsResponseDataMenuLock MenuLock { get; set; } = default!; + /// Indicates that the reader applied the settings update. + [JsonPropertyName("status")] + public UpdateReaderSettingsResponseDataStatus Status { get; set; } +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsResponseDataMenuLock.g.cs b/src/SumUp/Models/UpdateReaderSettingsResponseDataMenuLock.g.cs new file mode 100644 index 0000000..d1d5ecc --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsResponseDataMenuLock.g.cs @@ -0,0 +1,16 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// Settings included in the update. Omitted fields are not returned. +public sealed partial class UpdateReaderSettingsResponseDataMenuLock +{ + /// Whether menu lock is enabled. + [JsonPropertyName("enabled")] + public bool? Enabled { get; set; } + /// Four-digit PIN used to unlock the reader's menu. + [JsonPropertyName("passcode")] + public string? Passcode { get; set; } +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsResponseDataStatus.g.cs b/src/SumUp/Models/UpdateReaderSettingsResponseDataStatus.g.cs new file mode 100644 index 0000000..a8fa3d3 --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsResponseDataStatus.g.cs @@ -0,0 +1,14 @@ +// +#nullable enable + +namespace SumUp; + +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +[JsonConverter(typeof(EnumMemberJsonConverterFactory))] +public enum UpdateReaderSettingsResponseDataStatus +{ + [EnumMember(Value = "applied")] + Applied, +} \ No newline at end of file diff --git a/src/SumUp/Models/UpdateReaderSettingsUnprocessableEntity.g.cs b/src/SumUp/Models/UpdateReaderSettingsUnprocessableEntity.g.cs new file mode 100644 index 0000000..fb449c2 --- /dev/null +++ b/src/SumUp/Models/UpdateReaderSettingsUnprocessableEntity.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace SumUp; + +using System.Text.Json.Serialization; +/// The reader cannot complete the settings request, or the settings are invalid. +public sealed partial class UpdateReaderSettingsUnprocessableEntity +{ + [JsonPropertyName("errors")] + public JsonObject Errors { get; set; } = default!; +} \ No newline at end of file diff --git a/src/SumUp/ReadersClient.g.cs b/src/SumUp/ReadersClient.g.cs index a843f52..d4511d4 100644 --- a/src/SumUp/ReadersClient.g.cs +++ b/src/SumUp/ReadersClient.g.cs @@ -154,7 +154,7 @@ public async Task> CreateAsync(string merchantCode, ReadersC /// /// Create a Reader Checkout /// - /// Creates a Checkout for a Reader. This process is asynchronous and the actual transaction may take some time to be started on the device. There are some caveats when using this endpoint: * The target device must be online, otherwise checkout won't be accepted * After the checkout is accepted, the system has 60 seconds to start the payment on the target device. During this time, any other checkout for the same device will be rejected. Note: If the target device is a Solo, it must be in version 3.3.24.3 or higher. + /// Creates a Checkout for a Reader. This process is asynchronous and the actual transaction may take some time to be started on the device. There are some caveats when using this endpoint: * The target device must be online, otherwise checkout won't be accepted * After the checkout is accepted, the system has 60 seconds to start the payment on the target device. During this time, any other checkout for the same device will be rejected. Note: If the target device is a Solo, it must be in version 3.3.24.3 or higher. Optionally include an affiliate object to attach integrator metadata to the payment. Provide both app_id and key when including this object. /// Merchant Code /// The unique identifier of the Reader /// A checkout initial attributes @@ -225,7 +225,7 @@ public ApiResponse CreateCheckout(string merchantC /// /// Create a Reader Checkout /// - /// Creates a Checkout for a Reader. This process is asynchronous and the actual transaction may take some time to be started on the device. There are some caveats when using this endpoint: * The target device must be online, otherwise checkout won't be accepted * After the checkout is accepted, the system has 60 seconds to start the payment on the target device. During this time, any other checkout for the same device will be rejected. Note: If the target device is a Solo, it must be in version 3.3.24.3 or higher. + /// Creates a Checkout for a Reader. This process is asynchronous and the actual transaction may take some time to be started on the device. There are some caveats when using this endpoint: * The target device must be online, otherwise checkout won't be accepted * After the checkout is accepted, the system has 60 seconds to start the payment on the target device. During this time, any other checkout for the same device will be rejected. Note: If the target device is a Solo, it must be in version 3.3.24.3 or higher. Optionally include an affiliate object to attach integrator metadata to the payment. Provide both app_id and key when including this object. /// Merchant Code /// The unique identifier of the Reader /// A checkout initial attributes @@ -757,6 +757,128 @@ public async Task> GetCheckoutAsync(strin } } + /// + /// Get Reader Settings + /// + /// Returns the menu lock settings for a Solo reader. For an online reader, returns the current settings. For an offline reader, returns the last saved settings, which may differ from its current configuration. Returns 404 if the reader is offline and no saved settings are available. The response may include the menu lock PIN. + /// The merchant code of the account that owns the reader. + /// The unique identifier of the reader. + /// Optional per-request overrides. + /// Token used to cancel the request. + public ApiResponse GetReaderSettings(string merchantCode, string readerId, RequestOptions? requestOptions = null, CancellationToken cancellationToken = default) + { + var request = _client.CreateRequest(HttpMethod.Get, "/v0.1/merchants/{merchant_code}/readers/{reader_id}/settings", builder => + { + builder.AddPath("merchant_code", merchantCode); + builder.AddPath("reader_id", readerId); + }); + var effectiveCancellationToken = ApiClient.CreateCancellationToken(cancellationToken, requestOptions, out var timeoutScope); + try + { + _client.ApplyAuthorizationHeaderAsync(request, effectiveCancellationToken, requestOptions).GetAwaiter().GetResult(); + + using var response = _client.HttpClient.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead, + effectiveCancellationToken).GetAwaiter().GetResult(); + + if (!response.IsSuccessStatusCode) + { + var responseBody = response.Content is null + ? null + : ApiClient.ReadContentAsStringAsync(response.Content, effectiveCancellationToken).GetAwaiter().GetResult(); + switch ((int)response.StatusCode) + { + case 401: + { + var errorForStatus401 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus401, responseBody, response.RequestMessage?.RequestUri); + } + case 404: + { + var errorForStatus404 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus404, responseBody, response.RequestMessage?.RequestUri); + } + case 422: + { + var errorForStatus422 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus422, responseBody, response.RequestMessage?.RequestUri); + } + } + var fallbackError = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, fallbackError, responseBody, response.RequestMessage?.RequestUri); + } + using var stream = ApiClient.ReadContentAsStreamAsync(response.Content!, effectiveCancellationToken).GetAwaiter().GetResult(); + var result = JsonSerializer.Deserialize(stream, _client.SerializerOptions); + return ApiResponse.From(result, response.StatusCode, response.Headers, response.RequestMessage?.RequestUri); + } + finally + { + timeoutScope?.Dispose(); + } + } + + /// + /// Get Reader Settings + /// + /// Returns the menu lock settings for a Solo reader. For an online reader, returns the current settings. For an offline reader, returns the last saved settings, which may differ from its current configuration. Returns 404 if the reader is offline and no saved settings are available. The response may include the menu lock PIN. + /// The merchant code of the account that owns the reader. + /// The unique identifier of the reader. + /// Optional per-request overrides. + /// Token used to cancel the request. + public async Task> GetReaderSettingsAsync(string merchantCode, string readerId, RequestOptions? requestOptions = null, CancellationToken cancellationToken = default) + { + var request = _client.CreateRequest(HttpMethod.Get, "/v0.1/merchants/{merchant_code}/readers/{reader_id}/settings", builder => + { + builder.AddPath("merchant_code", merchantCode); + builder.AddPath("reader_id", readerId); + }); + var effectiveCancellationToken = ApiClient.CreateCancellationToken(cancellationToken, requestOptions, out var timeoutScope); + try + { + await _client.ApplyAuthorizationHeaderAsync(request, effectiveCancellationToken, requestOptions).ConfigureAwait(false); + + using var response = await _client.HttpClient.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead, + effectiveCancellationToken).ConfigureAwait(false); + + if (!response.IsSuccessStatusCode) + { + var responseBody = response.Content is null + ? null + : await ApiClient.ReadContentAsStringAsync(response.Content, effectiveCancellationToken).ConfigureAwait(false); + switch ((int)response.StatusCode) + { + case 401: + { + var errorForStatus401 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus401, responseBody, response.RequestMessage?.RequestUri); + } + case 404: + { + var errorForStatus404 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus404, responseBody, response.RequestMessage?.RequestUri); + } + case 422: + { + var errorForStatus422 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus422, responseBody, response.RequestMessage?.RequestUri); + } + } + var fallbackError = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, fallbackError, responseBody, response.RequestMessage?.RequestUri); + } + using var stream = await ApiClient.ReadContentAsStreamAsync(response.Content!, effectiveCancellationToken).ConfigureAwait(false); + var result = await JsonSerializer.DeserializeAsync(stream, _client.SerializerOptions, effectiveCancellationToken).ConfigureAwait(false); + return ApiResponse.From(result, response.StatusCode, response.Headers, response.RequestMessage?.RequestUri); + } + finally + { + timeoutScope?.Dispose(); + } + } + /// /// Get a Reader Status /// @@ -1230,4 +1352,146 @@ public async Task> UpdateAsync(string merchantCode, string r timeoutScope?.Dispose(); } } + + /// + /// Update Reader Settings + /// + /// Updates the menu lock settings for a Solo reader. The reader must be online. A successful response confirms that the reader applied the update. Include at least one of menu_lock.enabled or menu_lock.passcode. Omitted settings keep their current values. The response contains only the settings included in the request. When enabling menu lock for a reader without a PIN, include a four-digit PIN in menu_lock.passcode in the same request. + /// The merchant code of the account that owns the reader. + /// The unique identifier of the reader. + /// Menu lock settings to update. + /// Optional per-request overrides. + /// Token used to cancel the request. + public ApiResponse UpdateReaderSettings(string merchantCode, string readerId, UpdateReaderSettingsRequest body, RequestOptions? requestOptions = null, CancellationToken cancellationToken = default) + { + var request = _client.CreateRequest(new HttpMethod("PATCH"), "/v0.1/merchants/{merchant_code}/readers/{reader_id}/settings", builder => + { + builder.AddPath("merchant_code", merchantCode); + builder.AddPath("reader_id", readerId); + }); + var effectiveCancellationToken = ApiClient.CreateCancellationToken(cancellationToken, requestOptions, out var timeoutScope); + try + { + _client.ApplyAuthorizationHeaderAsync(request, effectiveCancellationToken, requestOptions).GetAwaiter().GetResult(); + if (body is not null && request.Content is null) + { + request.Content = _client.CreateContent(body, "application/json"); + } + + using var response = _client.HttpClient.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead, + effectiveCancellationToken).GetAwaiter().GetResult(); + + if (!response.IsSuccessStatusCode) + { + var responseBody = response.Content is null + ? null + : ApiClient.ReadContentAsStringAsync(response.Content, effectiveCancellationToken).GetAwaiter().GetResult(); + switch ((int)response.StatusCode) + { + case 400: + { + var errorForStatus400 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus400, responseBody, response.RequestMessage?.RequestUri); + } + case 401: + { + var errorForStatus401 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus401, responseBody, response.RequestMessage?.RequestUri); + } + case 404: + { + var errorForStatus404 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus404, responseBody, response.RequestMessage?.RequestUri); + } + case 422: + { + var errorForStatus422 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus422, responseBody, response.RequestMessage?.RequestUri); + } + } + var fallbackError = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, fallbackError, responseBody, response.RequestMessage?.RequestUri); + } + using var stream = ApiClient.ReadContentAsStreamAsync(response.Content!, effectiveCancellationToken).GetAwaiter().GetResult(); + var result = JsonSerializer.Deserialize(stream, _client.SerializerOptions); + return ApiResponse.From(result, response.StatusCode, response.Headers, response.RequestMessage?.RequestUri); + } + finally + { + timeoutScope?.Dispose(); + } + } + + /// + /// Update Reader Settings + /// + /// Updates the menu lock settings for a Solo reader. The reader must be online. A successful response confirms that the reader applied the update. Include at least one of menu_lock.enabled or menu_lock.passcode. Omitted settings keep their current values. The response contains only the settings included in the request. When enabling menu lock for a reader without a PIN, include a four-digit PIN in menu_lock.passcode in the same request. + /// The merchant code of the account that owns the reader. + /// The unique identifier of the reader. + /// Menu lock settings to update. + /// Optional per-request overrides. + /// Token used to cancel the request. + public async Task> UpdateReaderSettingsAsync(string merchantCode, string readerId, UpdateReaderSettingsRequest body, RequestOptions? requestOptions = null, CancellationToken cancellationToken = default) + { + var request = _client.CreateRequest(new HttpMethod("PATCH"), "/v0.1/merchants/{merchant_code}/readers/{reader_id}/settings", builder => + { + builder.AddPath("merchant_code", merchantCode); + builder.AddPath("reader_id", readerId); + }); + var effectiveCancellationToken = ApiClient.CreateCancellationToken(cancellationToken, requestOptions, out var timeoutScope); + try + { + await _client.ApplyAuthorizationHeaderAsync(request, effectiveCancellationToken, requestOptions).ConfigureAwait(false); + if (body is not null && request.Content is null) + { + request.Content = _client.CreateContent(body, "application/json"); + } + + using var response = await _client.HttpClient.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead, + effectiveCancellationToken).ConfigureAwait(false); + + if (!response.IsSuccessStatusCode) + { + var responseBody = response.Content is null + ? null + : await ApiClient.ReadContentAsStringAsync(response.Content, effectiveCancellationToken).ConfigureAwait(false); + switch ((int)response.StatusCode) + { + case 400: + { + var errorForStatus400 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus400, responseBody, response.RequestMessage?.RequestUri); + } + case 401: + { + var errorForStatus401 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus401, responseBody, response.RequestMessage?.RequestUri); + } + case 404: + { + var errorForStatus404 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus404, responseBody, response.RequestMessage?.RequestUri); + } + case 422: + { + var errorForStatus422 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus422, responseBody, response.RequestMessage?.RequestUri); + } + } + var fallbackError = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, fallbackError, responseBody, response.RequestMessage?.RequestUri); + } + using var stream = await ApiClient.ReadContentAsStreamAsync(response.Content!, effectiveCancellationToken).ConfigureAwait(false); + var result = await JsonSerializer.DeserializeAsync(stream, _client.SerializerOptions, effectiveCancellationToken).ConfigureAwait(false); + return ApiResponse.From(result, response.StatusCode, response.Headers, response.RequestMessage?.RequestUri); + } + finally + { + timeoutScope?.Dispose(); + } + } } \ No newline at end of file diff --git a/src/SumUp/SumUpClient.g.cs b/src/SumUp/SumUpClient.g.cs index bdd802d..ec8ccb8 100644 --- a/src/SumUp/SumUpClient.g.cs +++ b/src/SumUp/SumUpClient.g.cs @@ -18,6 +18,7 @@ partial void InitializeGeneratedClients(ApiClient apiClient) Readers = new ReadersClient(apiClient); Receipts = new ReceiptsClient(apiClient); Roles = new RolesClient(apiClient); + Tokens = new TokensClient(apiClient); Transactions = new TransactionsClient(apiClient); } @@ -66,6 +67,11 @@ partial void InitializeGeneratedClients(ApiClient apiClient) /// public RolesClient Roles { get; private set; } = default!; + /// + /// Access the Tokens API endpoints. + /// + public TokensClient Tokens { get; private set; } = default!; + /// /// Access the Transactions API endpoints. /// diff --git a/src/SumUp/TokensClient.g.cs b/src/SumUp/TokensClient.g.cs new file mode 100644 index 0000000..efa6e4e --- /dev/null +++ b/src/SumUp/TokensClient.g.cs @@ -0,0 +1,153 @@ +// +#nullable enable + +namespace SumUp; + +using System; +using System.Net.Http; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using SumUp.Http; + +public sealed partial class TokensClient +{ + private readonly ApiClient _client; + + /// + /// Client for the Tokens API endpoints. + /// + /// Merchant tokens let your application accept card-present payments with SumUp SDKs that support token-based authentication. Use them when you want users to sign in to your application with your own authentication, then accept payments for a SumUp merchant account. Create tokens on your backend using one of the supported authentication methods. Keep your authentication credentials on your backend. Return only the short-lived merchant token to your application and pass its access_token to the SDK. Before returning a token, authenticate the user in your application and check that they can accept payments for the requested merchant account. A merchant token is limited to that account and the requested actions, and does not grant permissions beyond those of the identity that created it. Tokens expire 15 minutes after creation. Use expires_in to determine the remaining lifetime and create a new token when needed. This endpoint does not return a refresh token. Treat merchant tokens as secrets: send them over HTTPS and keep them out of URLs, logs, and source code. + internal TokensClient(ApiClient client) + { + _client = client; + } + + /// + /// Create a merchant token + /// + /// Creates a short-lived token for the merchant account identified by merchant_code and the requested actions. Call this endpoint from your backend using a supported authentication method. You must have access to the merchant account. Before returning the token, check that the user signed in to your application is allowed to accept payments for that account. Pass the returned access_token to the SDK. The token expires 15 minutes after creation; use expires_in for its remaining lifetime. To continue after it expires, create a new token through this endpoint. + /// Unique code of the merchant account that will receive the payments. + /// Actions the merchant token should allow. + /// Optional per-request overrides. + /// Token used to cancel the request. + public ApiResponse Create(string merchantCode, TokensCreateRequest body, RequestOptions? requestOptions = null, CancellationToken cancellationToken = default) + { + var request = _client.CreateRequest(HttpMethod.Post, "/v0.1/merchants/{merchant_code}/tokens", builder => + { + builder.AddPath("merchant_code", merchantCode); + }); + var effectiveCancellationToken = ApiClient.CreateCancellationToken(cancellationToken, requestOptions, out var timeoutScope); + try + { + _client.ApplyAuthorizationHeaderAsync(request, effectiveCancellationToken, requestOptions).GetAwaiter().GetResult(); + if (body is not null && request.Content is null) + { + request.Content = _client.CreateContent(body, "application/json"); + } + + using var response = _client.HttpClient.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead, + effectiveCancellationToken).GetAwaiter().GetResult(); + + if (!response.IsSuccessStatusCode) + { + var responseBody = response.Content is null + ? null + : ApiClient.ReadContentAsStringAsync(response.Content, effectiveCancellationToken).GetAwaiter().GetResult(); + switch ((int)response.StatusCode) + { + case 400: + { + var errorForStatus400 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus400, responseBody, response.RequestMessage?.RequestUri); + } + case 401: + { + var errorForStatus401 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus401, responseBody, response.RequestMessage?.RequestUri); + } + case 403: + { + var errorForStatus403 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus403, responseBody, response.RequestMessage?.RequestUri); + } + } + var fallbackError = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, fallbackError, responseBody, response.RequestMessage?.RequestUri); + } + using var stream = ApiClient.ReadContentAsStreamAsync(response.Content!, effectiveCancellationToken).GetAwaiter().GetResult(); + var result = JsonSerializer.Deserialize(stream, _client.SerializerOptions); + return ApiResponse.From(result, response.StatusCode, response.Headers, response.RequestMessage?.RequestUri); + } + finally + { + timeoutScope?.Dispose(); + } + } + + /// + /// Create a merchant token + /// + /// Creates a short-lived token for the merchant account identified by merchant_code and the requested actions. Call this endpoint from your backend using a supported authentication method. You must have access to the merchant account. Before returning the token, check that the user signed in to your application is allowed to accept payments for that account. Pass the returned access_token to the SDK. The token expires 15 minutes after creation; use expires_in for its remaining lifetime. To continue after it expires, create a new token through this endpoint. + /// Unique code of the merchant account that will receive the payments. + /// Actions the merchant token should allow. + /// Optional per-request overrides. + /// Token used to cancel the request. + public async Task> CreateAsync(string merchantCode, TokensCreateRequest body, RequestOptions? requestOptions = null, CancellationToken cancellationToken = default) + { + var request = _client.CreateRequest(HttpMethod.Post, "/v0.1/merchants/{merchant_code}/tokens", builder => + { + builder.AddPath("merchant_code", merchantCode); + }); + var effectiveCancellationToken = ApiClient.CreateCancellationToken(cancellationToken, requestOptions, out var timeoutScope); + try + { + await _client.ApplyAuthorizationHeaderAsync(request, effectiveCancellationToken, requestOptions).ConfigureAwait(false); + if (body is not null && request.Content is null) + { + request.Content = _client.CreateContent(body, "application/json"); + } + + using var response = await _client.HttpClient.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead, + effectiveCancellationToken).ConfigureAwait(false); + + if (!response.IsSuccessStatusCode) + { + var responseBody = response.Content is null + ? null + : await ApiClient.ReadContentAsStringAsync(response.Content, effectiveCancellationToken).ConfigureAwait(false); + switch ((int)response.StatusCode) + { + case 400: + { + var errorForStatus400 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus400, responseBody, response.RequestMessage?.RequestUri); + } + case 401: + { + var errorForStatus401 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus401, responseBody, response.RequestMessage?.RequestUri); + } + case 403: + { + var errorForStatus403 = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, errorForStatus403, responseBody, response.RequestMessage?.RequestUri); + } + } + var fallbackError = _client.TryDeserialize(responseBody); + throw new ApiException(response.StatusCode, fallbackError, responseBody, response.RequestMessage?.RequestUri); + } + using var stream = await ApiClient.ReadContentAsStreamAsync(response.Content!, effectiveCancellationToken).ConfigureAwait(false); + var result = await JsonSerializer.DeserializeAsync(stream, _client.SerializerOptions, effectiveCancellationToken).ConfigureAwait(false); + return ApiResponse.From(result, response.StatusCode, response.Headers, response.RequestMessage?.RequestUri); + } + finally + { + timeoutScope?.Dispose(); + } + } +} \ No newline at end of file