diff --git a/codegen/pkg/builder/builder.go b/codegen/pkg/builder/builder.go index 019c26d..8776a53 100644 --- a/codegen/pkg/builder/builder.go +++ b/codegen/pkg/builder/builder.go @@ -93,6 +93,10 @@ func (b *Builder) Build() error { return fmt.Errorf("missing specs: call Load to load the specs first") } + if err := b.cleanupGeneratedResourceDirs(); err != nil { + return err + } + if err := b.generateSharedTypes(); err != nil { return err } diff --git a/codegen/pkg/builder/out.go b/codegen/pkg/builder/out.go index e96ced0..8077045 100644 --- a/codegen/pkg/builder/out.go +++ b/codegen/pkg/builder/out.go @@ -259,6 +259,56 @@ func writableUsesSecret(w Writable) bool { return false } +func (b *Builder) cleanupGeneratedResourceDirs() error { + entries, err := os.ReadDir(b.cfg.Out) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return fmt.Errorf("read output directory: %w", err) + } + + expected := make(map[string]struct{}, len(b.pathsByTag)) + for tagName := range b.pathsByTag { + tag := b.tagByTagName(tagName) + expected[strcase.ToSnake(tag.Name)] = struct{}{} + } + + for _, entry := range entries { + if !entry.IsDir() { + continue + } + + name := entry.Name() + if _, ok := expected[name]; ok { + continue + } + if !isGeneratedResourceDir(path.Join(b.cfg.Out, name)) { + continue + } + + if err := os.RemoveAll(path.Join(b.cfg.Out, name)); err != nil { + return fmt.Errorf("remove stale generated resource %q: %w", name, err) + } + } + + return nil +} + +func isGeneratedResourceDir(dir string) bool { + resourceFile := path.Join(dir, "resource.py") + indexFile := path.Join(dir, "__init__.py") + + if _, err := os.Stat(resourceFile); err != nil { + return false + } + if _, err := os.Stat(indexFile); err != nil { + return false + } + + return true +} + func (b *Builder) writeClientFile(fname string, tags []string) error { f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(0o755)) if err != nil { diff --git a/openapi.json b/openapi.json index b838c21..cc9d3e6 100755 --- a/openapi.json +++ b/openapi.json @@ -1900,10 +1900,20 @@ ] } }, - "/v0.1/me/refund/{txn_id}": { + "/v1.0/merchants/{merchant_code}/payments/{id}/refunds": { "parameters": [ { - "name": "txn_id", + "name": "merchant_code", + "in": "path", + "description": "Merchant code of the account that owns the payment to refund.", + "required": true, + "schema": { + "type": "string", + "example": "MH4H92C7" + } + }, + { + "name": "id", "in": "path", "description": "Unique ID of the transaction.", "required": true, @@ -2149,121 +2159,6 @@ ] } }, - "/v0.1/me/transactions": { - "get": { - "operationId": "GetTransaction", - "summary": "Retrieve a transaction", - "description": "Retrieves the full details of an identified transaction. The transaction resource is identified by a query parameter and *one* of following parameters is required:\n- `id`\n- `transaction_code`\n- `foreign_transaction_id`\n- `client_transaction_id`", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "Retrieves the transaction resource with the specified transaction ID (the `id` parameter in the transaction resource).", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "transaction_code", - "in": "query", - "description": "Retrieves the transaction resource with the specified transaction code.", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Returns the requested transaction resource.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TransactionFull" - }, - "example": { - "id": "410fc44a-5956-44e1-b5cc-19c6f8d727a4", - "transaction_code": "TEENSK4W2K", - "amount": 10.1, - "currency": "EUR", - "timestamp": "2020-02-29T10:56:56.876Z", - "status": "SUCCESSFUL", - "payment_type": "ECOM", - "installments_count": 1, - "merchant_code": "MH4H92C7", - "vat_amount": 6, - "tip_amount": 3, - "entry_mode": "CUSTOMER_ENTRY", - "auth_code": "053201" - } - } - } - }, - "401": { - "description": "The request is not authorized.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Problem" - }, - "examples": { - "Problem_Details": { - "description": "Unauthorized response returned by API gateway.", - "value": { - "detail": "Unauthorized.", - "status": 401, - "title": "Unauthorized", - "trace_id": "3c77294349d3b5647ea2d990f0d8f017", - "type": "https://developer.sumup.com/problem/unauthorized" - } - } - } - } - } - }, - "404": { - "description": "The requested resource does not exist.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - }, - "examples": { - "Not_Found": { - "description": "The identified resource is not found on the server.", - "value": { - "error_code": "NOT_FOUND", - "message": "Resource not found" - } - } - } - } - } - } - }, - "deprecated": true, - "security": [ - { - "apiKey": [] - }, - { - "oauth2": [ - "transactions.history" - ] - } - ], - "tags": [ - "Transactions" - ], - "x-codegen": { - "method_name": "get_deprecated" - }, - "x-scopes": [ - "transactions.history" - ] - } - }, "/v2.1/merchants/{merchant_code}/transactions/history": { "get": { "operationId": "ListTransactionsV2.1", @@ -2566,383 +2461,115 @@ ] } }, - "/v0.1/me/transactions/history": { + "/v1.0/merchants/{merchant_code}/payouts": { "get": { - "operationId": "ListTransactions", - "summary": "List transactions", - "description": "Lists detailed history of all transactions associated with the merchant profile.", + "operationId": "ListPayoutsV1", + "summary": "List payouts", + "description": "Lists payout and payout-deduction records for the specified merchant account within the requested date range.\n\nThe response can include:\n- regular payouts (`type = PAYOUT`)\n- deduction records for refunds, chargebacks, direct debit returns, or balance adjustments\n\nResults are sorted by payout date in the requested `order`.", "parameters": [ { - "name": "transaction_code", - "in": "query", - "description": "Retrieves the transaction resource with the specified transaction code.", - "required": false, + "name": "merchant_code", + "in": "path", + "description": "Merchant code of the account whose payouts should be listed.", + "required": true, "schema": { - "type": "string" + "type": "string", + "example": "MH4H92C7" } }, { - "name": "order", + "name": "start_date", "in": "query", - "description": "Specifies the order in which the returned results are displayed.", + "description": "Start date of the payout period filter, inclusive, in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) `date` format (`YYYY-MM-DD`).", + "required": true, "schema": { "type": "string", - "default": "ascending", - "enum": [ - "ascending", - "descending" - ] + "format": "date", + "example": "2024-02-01" } }, { - "name": "limit", + "name": "end_date", "in": "query", - "description": "Specifies the maximum number of results per page. Value must be a positive integer and if not specified, will return 10 results.", + "description": "End date of the payout period filter, inclusive, in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) `date` format (`YYYY-MM-DD`). Must be greater than or equal to `start_date`.", + "required": true, "schema": { - "type": "integer" + "type": "string", + "format": "date", + "example": "2024-02-29" } }, { - "name": "users", + "name": "format", "in": "query", - "description": "Filters the returned results by user email.", + "description": "Response format for the payout list.", "required": false, "schema": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "example": [ - "merchant@example.com" + "type": "string", + "example": "json", + "default": "json", + "enum": [ + "json", + "csv" ] - }, - "example": [ - "merchant@example.com" - ] - }, - { - "name": "statuses[]", - "in": "query", - "description": "Filters the returned results by the specified list of final statuses of the transactions.", - "required": false, - "schema": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "SUCCESSFUL", - "CANCELLED", - "FAILED", - "REFUNDED", - "CHARGE_BACK" - ] - } } }, { - "name": "payment_types", + "name": "limit", "in": "query", - "description": "Filters the returned results by the specified list of payment types used for the transactions.", + "description": "Maximum number of payout records to return.", "required": false, "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentType" - } + "type": "integer", + "example": 10, + "maximum": 9999, + "minimum": 1 } }, { - "name": "types", + "name": "order", "in": "query", - "description": "Filters the returned results by the specified list of transaction types.", + "description": "Sort direction for the returned payouts.", "required": false, "schema": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "PAYMENT", - "REFUND", - "CHARGE_BACK" - ] - } - } - }, - { - "name": "changes_since", - "in": "query", - "description": "Filters the results by the latest modification time of resources and returns only transactions that are modified *at or after* the specified timestamp (in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format).", - "required": false, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "newest_time", - "in": "query", - "description": "Filters the results by the creation time of resources and returns only transactions that are created *before* the specified timestamp (in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format).", - "required": false, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "newest_ref", - "in": "query", - "description": "Filters the results by the reference ID of transaction events and returns only transactions with events whose IDs are *smaller* than the specified value. This parameters supersedes the `newest_time` parameter (if both are provided in the request).", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "oldest_time", - "in": "query", - "description": "Filters the results by the creation time of resources and returns only transactions that are created *at or after* the specified timestamp (in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format).", - "required": false, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "oldest_ref", - "in": "query", - "description": "Filters the results by the reference ID of transaction events and returns only transactions with events whose IDs are *greater* than the specified value. This parameters supersedes the `oldest_time` parameter (if both are provided in the request).", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Returns a page of transaction history items.", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TransactionHistory" - }, - "example": [ - { - "transaction_code": "TEENSK4W2K", - "amount": 10.1, - "currency": "EUR", - "timestamp": "2020-02-29T10:56:56.876Z", - "status": "SUCCESSFUL", - "payment_type": "ECOM", - "installments_count": 1, - "merchant_code": "MH4H92C7", - "transaction_id": "410fc44a-5956-44e1-b5cc-19c6f8d727a4", - "user": "merchant@example.com", - "type": "PAYMENT", - "payout_date": "2019-08-28", - "payout_type": "BANK_ACCOUNT", - "refunded_amount": 0 - } - ] - }, - "links": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TransactionsHistoryLink" - }, - "example": [] - } - } - }, - "example": { - "items": [ - { - "transaction_code": "TEENSK4W2K", - "amount": 10.1, - "currency": "EUR", - "timestamp": "2020-02-29T10:56:56.876Z", - "status": "SUCCESSFUL", - "payment_type": "ECOM", - "installments_count": 1, - "merchant_code": "MH4H92C7", - "transaction_id": "410fc44a-5956-44e1-b5cc-19c6f8d727a4", - "user": "merchant@example.com", - "type": "PAYMENT", - "payout_date": "2019-08-28", - "payout_type": "BANK_ACCOUNT", - "refunded_amount": 0 - } - ], - "links": [] - } - } - } - }, - "400": { - "description": "The request is invalid for the submitted query parameters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - }, - "examples": { - "Invalid_Parameter": { - "description": "A request parameter has an invalid value.", - "value": { - "message": "Validation error", - "error_code": "INVALID" - } - } - } - } - } - }, - "401": { - "description": "The request is not authorized.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Problem" - }, - "examples": { - "Problem_Details": { - "description": "Unauthorized response returned by API gateway.", - "value": { - "detail": "Unauthorized.", - "status": 401, - "title": "Unauthorized", - "trace_id": "3c77294349d3b5647ea2d990f0d8f017", - "type": "https://developer.sumup.com/problem/unauthorized" - } - } - } - } - } - } - }, - "deprecated": true, - "security": [ - { - "apiKey": [] - }, - { - "oauth2": [ - "transactions.history" - ] - } - ], - "tags": [ - "Transactions" - ], - "x-codegen": { - "method_name": "list_deprecated" - }, - "x-scopes": [ - "transactions.history" - ] - } - }, - "/v1.0/merchants/{merchant_code}/payouts": { - "get": { - "operationId": "ListPayoutsV1", - "summary": "List payouts", - "description": "Lists ordered payouts for the merchant account.", - "parameters": [ - { - "name": "merchant_code", - "in": "path", - "description": "Merchant code of the account whose payouts should be listed.", - "required": true, - "schema": { - "type": "string", - "example": "MH4H92C7" - } - }, - { - "name": "start_date", - "in": "query", - "description": "Start date (in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format).", - "required": true, - "schema": { - "type": "string", - "format": "date" - } - }, - { - "name": "end_date", - "in": "query", - "description": "End date (in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format).", - "required": true, - "schema": { - "type": "string", - "format": "date" - } - }, - { - "name": "format", - "in": "query", - "description": "Response format for the payout list.", - "required": false, - "schema": { - "type": "string", - "example": "json", - "enum": [ - "json", - "csv" - ] - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of payout records to return.", - "required": false, - "schema": { - "type": "integer", - "example": 10 - } - }, - { - "name": "order", - "in": "query", - "description": "Sort direction for the returned payouts.", - "required": false, - "schema": { - "type": "string", - "example": "desc", - "enum": [ - "desc", - "asc" - ] - } - } - ], - "responses": { - "200": { - "description": "Returns the list of payouts for the requested period.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FinancialPayouts" - }, - "example": [ - { - "amount": 132.45, - "currency": "EUR", - "date": "2024-02-29", - "fee": 3.12, - "id": 123456789, - "reference": "payout-2024-02-29", - "status": "SUCCESSFUL", - "transaction_code": "TEENSK4W2K", - "type": "PAYOUT" - } + "type": "string", + "example": "desc", + "default": "asc", + "enum": [ + "asc", + "desc" + ] + } + } + ], + "responses": { + "200": { + "description": "Returns the list of payout and deduction records for the requested period.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FinancialPayouts" + }, + "example": [ + { + "amount": 132.45, + "currency": "EUR", + "date": "2024-02-29", + "fee": 3.12, + "id": 123456789, + "reference": "payout-2024-02-29", + "status": "SUCCESSFUL", + "transaction_code": "TEENSK4W2K", + "type": "PAYOUT" + } ] + }, + "text/plain": { + "schema": { + "description": "CSV-formatted payout export returned when `format=csv`.", + "type": "string" + }, + "example": "id,type,amount,date,currency,fee,status,reference,transaction_code\n123456789,PAYOUT,132.45,2024-02-29,EUR,3.12,SUCCESSFUL,payout-2024-02-29,TEENSK4W2K" } } }, @@ -2957,7 +2584,7 @@ } }, "examples": { - "Missing_Required_Dates": { + "Missing required dates": { "description": "Required date filters are missing.", "value": [ { @@ -2971,169 +2598,13 @@ "param": "end_date" } ] - } - } - } - } - }, - "401": { - "description": "The request is not authorized.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Problem" - }, - "examples": { - "Problem_Details": { - "description": "Unauthorized response returned by API gateway.", - "value": { - "detail": "Unauthorized.", - "status": 401, - "title": "Unauthorized", - "trace_id": "3c77294349d3b5647ea2d990f0d8f017", - "type": "https://developer.sumup.com/problem/unauthorized" - } - } - } - } - } - } - }, - "security": [ - { - "apiKey": [] - }, - { - "oauth2": [ - "user.profile", - "user.profile_readonly" - ] - } - ], - "tags": [ - "Payouts" - ], - "x-codegen": { - "method_name": "list" - }, - "x-scopes": [ - "user.profile", - "user.profile_readonly" - ] - } - }, - "/v0.1/me/financials/payouts": { - "get": { - "operationId": "ListPayouts", - "summary": "List payouts", - "description": "Lists ordered payouts for the merchant account.", - "parameters": [ - { - "name": "start_date", - "in": "query", - "description": "Start date (in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format).", - "required": true, - "schema": { - "type": "string", - "format": "date" - } - }, - { - "name": "end_date", - "in": "query", - "description": "End date (in [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format).", - "required": true, - "schema": { - "type": "string", - "format": "date" - } - }, - { - "name": "format", - "in": "query", - "description": "Response format for the payout list.", - "required": false, - "schema": { - "type": "string", - "example": "json", - "enum": [ - "json", - "csv" - ] - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of payout records to return.", - "required": false, - "schema": { - "type": "integer", - "example": 10 - } - }, - { - "name": "order", - "in": "query", - "description": "Sort direction for the returned payouts.", - "required": false, - "schema": { - "type": "string", - "example": "desc", - "enum": [ - "desc", - "asc" - ] - } - } - ], - "responses": { - "200": { - "description": "Returns the list of payouts for the requested period.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FinancialPayouts" - }, - "example": [ - { - "amount": 132.45, - "currency": "EUR", - "date": "2024-02-29", - "fee": 3.12, - "id": 123456789, - "reference": "payout-2024-02-29", - "status": "SUCCESSFUL", - "transaction_code": "TEENSK4W2K", - "type": "PAYOUT" - } - ] - } - } - }, - "400": { - "description": "The request is invalid for the submitted query parameters.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ErrorExtended" - } - }, - "examples": { - "Missing_Required_Dates": { - "description": "Required date filters are missing.", + }, + "Invalid date range": { + "description": "`start_date` cannot be later than `end_date`.", "value": [ { - "error_code": "MISSING", - "message": "Validation error: required", - "param": "start_date" - }, - { - "error_code": "MISSING", - "message": "Validation error: required", - "param": "end_date" + "error_code": "INVALID", + "message": "negative date range" } ] } @@ -3142,524 +2613,182 @@ } }, "401": { - "description": "The request is not authorized.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Problem" - }, - "examples": { - "Problem_Details": { - "description": "Unauthorized response returned by API gateway.", - "value": { - "detail": "Unauthorized.", - "status": 401, - "title": "Unauthorized", - "trace_id": "3c77294349d3b5647ea2d990f0d8f017", - "type": "https://developer.sumup.com/problem/unauthorized" - } - } - } - } - } - } - }, - "deprecated": true, - "security": [ - { - "apiKey": [] - }, - { - "oauth2": [ - "user.profile", - "user.profile_readonly" - ] - } - ], - "tags": [ - "Payouts" - ], - "x-codegen": { - "method_name": "list_deprecated" - }, - "x-scopes": [ - "user.profile", - "user.profile_readonly" - ] - } - }, - "/v1.1/receipts/{id}": { - "get": { - "operationId": "GetReceipt", - "summary": "Retrieve receipt details", - "description": "Retrieves receipt specific data for a transaction.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "SumUp unique transaction ID or transaction code, e.g. TS7HDYLSKD.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "mid", - "in": "query", - "description": "Merchant code.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "tx_event_id", - "in": "query", - "description": "The ID of the transaction event (refund).", - "required": false, - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "description": "Returns receipt details for the requested transaction.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Receipt" - }, - "example": { - "transaction_data": { - "transaction_code": "TEENSK4W2K", - "transaction_id": "410fc44a-5956-44e1-b5cc-19c6f8d727a4", - "merchant_code": "MH4H92C7", - "amount": "10.10", - "vat_amount": "6.00", - "tip_amount": "3.00", - "currency": "EUR", - "timestamp": "2020-02-29T10:56:56.876Z", - "status": "SUCCESSFUL", - "payment_type": "ECOM", - "entry_mode": "CUSTOMER_ENTRY", - "installments_count": 1, - "process_as": "CREDIT" - }, - "merchant_data": { - "merchant_profile": { - "merchant_code": "MH4H92C7" - } - }, - "acquirer_data": { - "authorization_code": "053201" - } - } - } - } - }, - "400": { - "description": "The request is invalid for the submitted parameters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - }, - "examples": { - "Invalid_Merchant_Code": { - "description": "The provided merchant code is invalid.", - "value": { - "message": "is not a valid merchant code", - "error_code": "INVALID" - } - } - } - } - } - }, - "401": { - "description": "The request is not authorized.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Problem" - }, - "examples": { - "Problem_Details": { - "description": "Unauthorized response returned by API gateway.", - "value": { - "detail": "Unauthorized.", - "status": 401, - "title": "Unauthorized", - "trace_id": "3c77294349d3b5647ea2d990f0d8f017", - "type": "https://developer.sumup.com/problem/unauthorized" - } - } - } - } - } - }, - "404": { - "description": "The requested transaction event does not exist for the provided transaction.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - }, - "examples": { - "Event_Not_Found": { - "description": "The provided transaction event ID cannot be found for this transaction.", - "value": { - "message": "No such tx event (ID=9567461191) for transaction 4ffb8dfc-7f2b-413d-a497-2ad00766585e", - "error_code": "NOT_FOUND" - } - } - } - } - } - } - }, - "security": [ - { - "apiKey": [] - }, - { - "oauth2": [] - } - ], - "tags": [ - "Receipts" - ], - "x-codegen": { - "method_name": "get" - }, - "x-scopes": [] - } - }, - "/v0.1/me/accounts": { - "get": { - "operationId": "ListSubAccounts", - "summary": "List operators", - "description": "Returns list of operators for currently authorized user's merchant.", - "parameters": [ - { - "name": "query", - "in": "query", - "description": "Search query used to filter users that match given query term.\n\nCurrent implementation allow querying only over the email address.\nAll operators whos email address contains the query string are returned.", - "schema": { - "type": "string" - } - }, - { - "name": "include_primary", - "in": "query", - "description": "If true the list of operators will include also the primary user.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "List of operators.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Operator" - } - } - } - } - }, - "401": { - "description": "Authentication failed or missing required scope.", - "content": { - "application/problem+json": { - "schema": { - "$ref": "#/components/schemas/Problem" - }, - "example": { - "type": "https://developer.sumup.com/problem/unauthorized", - "title": "Unauthorized", - "status": 401, - "detail": "Authentication credentials are missing or invalid." - } - } - } - } - }, - "deprecated": true, - "security": [ - { - "apiKey": [] - }, - { - "oauth2": [] - } - ], - "tags": [ - "Subaccounts" - ], - "x-deprecation-notice": "Subaccounts API is deprecated, to list users in your merchant account please use [List members](https://developer.sumup.com/api/members/list) instead.", - "x-permissions": [ - "members_list" - ], - "x-scopes": [] - }, - "post": { - "operationId": "CreateSubAccount", - "summary": "Create an operator", - "description": "Creates new operator for currently authorized users' merchant.", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "username": { - "type": "string", - "format": "email", - "example": "operator1@mydomain.com" - }, - "password": { - "type": "string", - "example": "correct horse batter staple", - "minLength": 8 - }, - "nickname": { - "type": "string", - "example": "Operator 1" - }, - "permissions": { - "type": "object", - "properties": { - "create_moto_payments": { - "type": "boolean" - }, - "create_referral": { - "type": "boolean" - }, - "full_transaction_history_view": { - "type": "boolean" - }, - "refund_transactions": { - "type": "boolean" - } - } - } - }, - "required": [ - "username", - "password" - ] - } - } - } - }, - "responses": { - "200": { - "description": "Newly created operator.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Operator" - } - } - } - }, - "403": { - "description": "Operator creation was forbidden.", + "description": "The request is not authorized.", "content": { - "application/problem+json": { + "application/json": { "schema": { "$ref": "#/components/schemas/Problem" }, - "example": { - "type": "https://developer.sumup.com/problem/forbidden", - "title": "Forbidden", - "status": 403, - "detail": "You do not have permission to perform this action." + "examples": { + "Problem_Details": { + "description": "Unauthorized response returned by API gateway.", + "value": { + "detail": "Unauthorized.", + "status": 401, + "title": "Unauthorized", + "trace_id": "3c77294349d3b5647ea2d990f0d8f017", + "type": "https://developer.sumup.com/problem/unauthorized" + } + } } } } } }, - "deprecated": true, "security": [ { "apiKey": [] }, { - "oauth2": [] + "oauth2": [ + "user.profile", + "user.profile_readonly" + ] } ], "tags": [ - "Subaccounts" - ], - "x-deprecation-notice": "Subaccounts API is deprecated, to create a user in your merchant account please use [Create member](https://developer.sumup.com/api/members/create) instead.", - "x-permissions": [ - "members_update" + "Payouts" ], - "x-scopes": [] + "x-codegen": { + "method_name": "list" + }, + "x-scopes": [ + "user.profile", + "user.profile_readonly" + ] } }, - "/v0.1/me/accounts/{operator_id}": { + "/v1.1/receipts/{id}": { "get": { - "operationId": "CompatGetOperator", - "summary": "Retrieve an operator", - "description": "Returns specific operator.", + "operationId": "GetReceipt", + "summary": "Retrieve receipt details", + "description": "Retrieves receipt specific data for a transaction.", "parameters": [ { - "name": "operator_id", + "name": "id", "in": "path", - "description": "The unique identifier for the operator.", + "description": "SumUp unique transaction ID or transaction code, e.g. TS7HDYLSKD.", "required": true, "schema": { - "type": "integer", - "format": "int32" + "type": "string" + } + }, + { + "name": "mid", + "in": "query", + "description": "Merchant code.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "tx_event_id", + "in": "query", + "description": "The ID of the transaction event (refund).", + "required": false, + "schema": { + "type": "integer" } } ], "responses": { "200": { - "description": "Information about the requested operator.", + "description": "Returns receipt details for the requested transaction.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Operator" + "$ref": "#/components/schemas/Receipt" + }, + "example": { + "transaction_data": { + "transaction_code": "TEENSK4W2K", + "transaction_id": "410fc44a-5956-44e1-b5cc-19c6f8d727a4", + "merchant_code": "MH4H92C7", + "amount": "10.10", + "vat_amount": "6.00", + "tip_amount": "3.00", + "currency": "EUR", + "timestamp": "2020-02-29T10:56:56.876Z", + "status": "SUCCESSFUL", + "payment_type": "ECOM", + "entry_mode": "CUSTOMER_ENTRY", + "installments_count": 1, + "process_as": "CREDIT" + }, + "merchant_data": { + "merchant_profile": { + "merchant_code": "MH4H92C7" + } + }, + "acquirer_data": { + "authorization_code": "053201" + } } } } }, - "401": { - "description": "Authentication failed or missing required scope.", + "400": { + "description": "The request is invalid for the submitted parameters.", "content": { - "application/problem+json": { + "application/json": { "schema": { - "$ref": "#/components/schemas/Problem" + "$ref": "#/components/schemas/Error" }, - "example": { - "type": "https://developer.sumup.com/problem/unauthorized", - "title": "Unauthorized", - "status": 401, - "detail": "Authentication credentials are missing or invalid." - } - } - } - } - }, - "deprecated": true, - "security": [ - { - "apiKey": [] - }, - { - "oauth2": [] - } - ], - "tags": [ - "Subaccounts" - ], - "x-deprecation-notice": "Subaccounts API is deprecated, to get a user that's a member of your merchant account please use [Get member](https://developer.sumup.com/api/members/get) instead.", - "x-permissions": [ - "members_view" - ], - "x-scopes": [] - }, - "put": { - "operationId": "UpdateSubAccount", - "summary": "Update an operator", - "description": "Updates operator. If the operator was disabled and their password is updated they will be unblocked.", - "parameters": [ - { - "name": "operator_id", - "in": "path", - "description": "The unique identifier for the operator.", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "password": { - "type": "string", - "example": "correct horse batter staple", - "minLength": 8 - }, - "username": { - "type": "string", - "format": "email", - "maxLength": 256 - }, - "disabled": { - "type": "boolean" - }, - "nickname": { - "type": "string", - "example": "Operator 1" - }, - "permissions": { - "type": "object", - "properties": { - "create_moto_payments": { - "type": "boolean" - }, - "create_referral": { - "type": "boolean" - }, - "full_transaction_history_view": { - "type": "boolean" - }, - "refund_transactions": { - "type": "boolean" - } + "examples": { + "Invalid_Merchant_Code": { + "description": "The provided merchant code is invalid.", + "value": { + "message": "is not a valid merchant code", + "error_code": "INVALID" } } } } } - } - }, - "responses": { - "200": { - "description": "Updated operator.", + }, + "401": { + "description": "The request is not authorized.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Operator" + "$ref": "#/components/schemas/Problem" + }, + "examples": { + "Problem_Details": { + "description": "Unauthorized response returned by API gateway.", + "value": { + "detail": "Unauthorized.", + "status": 401, + "title": "Unauthorized", + "trace_id": "3c77294349d3b5647ea2d990f0d8f017", + "type": "https://developer.sumup.com/problem/unauthorized" + } + } } } } }, - "400": { - "description": "Invalid Operators' email or password was already used.", + "404": { + "description": "The requested transaction event does not exist for the provided transaction.", "content": { - "application/problem+json": { + "application/json": { "schema": { - "$ref": "#/components/schemas/Problem" + "$ref": "#/components/schemas/Error" }, - "example": { - "type": "https://developer.sumup.com/problem/bad-request", - "title": "Bad Request", - "status": 400, - "detail": "Request validation failed." + "examples": { + "Event_Not_Found": { + "description": "The provided transaction event ID cannot be found for this transaction.", + "value": { + "message": "No such tx event (ID=9567461191) for transaction 4ffb8dfc-7f2b-413d-a497-2ad00766585e", + "error_code": "NOT_FOUND" + } + } } } } } }, - "deprecated": true, "security": [ { "apiKey": [] @@ -3669,12 +2798,11 @@ } ], "tags": [ - "Subaccounts" - ], - "x-deprecation-notice": "Subaccounts API is deprecated, to update a user that's a member of your merchant account please use [Update member](https://developer.sumup.com/api/members/update) instead.", - "x-permissions": [ - "members_update" + "Receipts" ], + "x-codegen": { + "method_name": "get" + }, "x-scopes": [] } }, @@ -7244,55 +6372,89 @@ "title": "Event" }, "FinancialPayouts": { - "description": "List of payout summaries.", + "description": "Ordered list of payout and payout-deduction records.", "type": "array", "items": { - "type": "object", - "properties": { - "amount": { - "type": "number", - "format": "float" - }, - "currency": { - "type": "string" - }, - "date": { - "type": "string", - "format": "date" - }, - "fee": { - "type": "number", - "format": "float" - }, - "id": { - "type": "integer" - }, - "reference": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "SUCCESSFUL", - "FAILED" - ] - }, - "transaction_code": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "PAYOUT", - "CHARGE_BACK_DEDUCTION", - "REFUND_DEDUCTION", - "DD_RETURN_DEDUCTION", - "BALANCE_DEDUCTION" - ] - } + "$ref": "#/components/schemas/FinancialPayout" + }, + "title": "Financial Payouts" + }, + "FinancialPayout": { + "description": "A single payout-related record.\n\nA record can represent either:\n- an actual payout sent to the merchant (`type = PAYOUT`)\n- a deduction applied against merchant funds for a refund, chargeback, direct debit return, or balance adjustment", + "type": "object", + "properties": { + "id": { + "description": "Unique identifier of the payout-related record.", + "type": "integer", + "example": 123456789 + }, + "type": { + "description": "High-level payout record category.", + "type": "string", + "example": "PAYOUT", + "enum": [ + "PAYOUT", + "CHARGE_BACK_DEDUCTION", + "REFUND_DEDUCTION", + "DD_RETURN_DEDUCTION", + "BALANCE_DEDUCTION" + ] + }, + "amount": { + "description": "Amount of the payout or deduction in major units.", + "type": "number", + "format": "float", + "example": 132.45 + }, + "date": { + "description": "Payout date associated with the record, in `YYYY-MM-DD` format.", + "type": "string", + "format": "date", + "example": "2024-02-29" + }, + "currency": { + "description": "Three-letter ISO 4217 currency code of the payout.", + "type": "string", + "example": "EUR" + }, + "fee": { + "description": "Fee amount associated with the payout record, in major units.", + "type": "number", + "format": "float", + "example": 3.12 + }, + "status": { + "description": "Merchant-facing outcome of the payout record.", + "type": "string", + "example": "SUCCESSFUL", + "enum": [ + "SUCCESSFUL", + "FAILED" + ] + }, + "reference": { + "description": "Processor or payout reference associated with the record.", + "type": "string", + "example": "payout-2024-02-29" + }, + "transaction_code": { + "description": "Transaction code of the original sale associated with the payout or deduction.", + "type": "string", + "example": "TEENSK4W2K" } }, - "title": "Financial Payouts" + "required": [ + "id", + "type", + "amount", + "date", + "currency", + "fee", + "status", + "reference", + "transaction_code" + ], + "title": "Financial Payout" }, "Link": { "description": "Details of a link to a related resource.", @@ -8467,331 +7629,84 @@ "Currency": { "description": "Three-letter [ISO4217](https://en.wikipedia.org/wiki/ISO_4217) code of the currency for the amount. Currently supported currency values are enumerated above.", "type": "string", - "example": "EUR", - "enum": [ - "BGN", - "BRL", - "CHF", - "CLP", - "COP", - "CZK", - "DKK", - "EUR", - "GBP", - "HRK", - "HUF", - "NOK", - "PLN", - "RON", - "SEK", - "USD" - ], - "title": "Currency" - }, - "EventType": { - "description": "Type of the transaction event.", - "type": "string", - "enum": [ - "PAYOUT", - "CHARGE_BACK", - "REFUND", - "PAYOUT_DEDUCTION" - ], - "title": "Event Type" - }, - "EventStatus": { - "description": "Status of the transaction event.\n\nNot every value is used for every event type.\n\n- `PENDING`: The event has been created but is not final yet. Used for events that are still being processed and whose final outcome is not known yet.\n- `SCHEDULED`: The event is planned for a future payout cycle but has not been executed yet. This applies to payout events before money is actually sent out.\n- `RECONCILED`: The underlying payment has been matched with settlement data and is ready to continue through payout processing, but the funds have not been paid out yet. This applies to payout events.\n- `PAID_OUT`: The payout event has been completed and the funds were included in a merchant payout.\n- `REFUNDED`: A refund event has been accepted and recorded in the refund flow. This is the status returned for refund events once the transaction amount is being or has been returned to the payer.\n- `SUCCESSFUL`: The event completed successfully. Use this as the generic terminal success status for event types that do not expose a more specific business outcome such as `PAID_OUT` or `REFUNDED`.\n- `FAILED`: The event could not be completed. Typical examples are a payout that could not be executed or an event that was rejected during processing.", - "type": "string", - "enum": [ - "FAILED", - "PAID_OUT", - "PENDING", - "RECONCILED", - "REFUNDED", - "SCHEDULED", - "SUCCESSFUL" - ], - "title": "Event Status" - }, - "EventID": { - "description": "Unique ID of the transaction event.", - "type": "integer", - "format": "int64", - "title": "Event ID" - }, - "HorizontalAccuracy": { - "description": "Indication of the precision of the geographical position received from the payment terminal.", - "type": "number", - "format": "float", - "title": "Horizontal Accuracy" - }, - "Lat": { - "description": "Latitude value from the coordinates of the payment location (as received from the payment terminal reader).", - "type": "number", - "format": "float", - "maximum": 90, - "minimum": 0, - "title": "Latitude" - }, - "Lon": { - "description": "Longitude value from the coordinates of the payment location (as received from the payment terminal reader).", - "type": "number", - "format": "float", - "maximum": 180, - "minimum": 0, - "title": "Longitude" - }, - "TransactionID": { - "description": "Unique ID of the transaction.", - "type": "string", - "title": "Transaction ID" - }, - "Permissions": { - "description": "Permissions assigned to an operator or user.", - "type": "object", - "properties": { - "create_moto_payments": { - "type": "boolean" - }, - "create_referral": { - "type": "boolean" - }, - "full_transaction_history_view": { - "type": "boolean" - }, - "refund_transactions": { - "type": "boolean" - }, - "admin": { - "type": "boolean" - } - }, - "required": [ - "create_moto_payments", - "create_referral", - "full_transaction_history_view", - "refund_transactions", - "admin" - ] - }, - "Operator": { - "description": "Operator account for a merchant.", - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "username": { - "type": "string", - "example": "operator1@mydomain.com" - }, - "nickname": { - "type": "string", - "example": "Operator 1", - "nullable": true - }, - "disabled": { - "type": "boolean", - "example": false - }, - "created_at": { - "description": "The timestamp of when the operator was created.", - "type": "string", - "format": "date-time" - }, - "updated_at": { - "description": "The timestamp of when the operator was last updated.", - "type": "string", - "format": "date-time" - }, - "permissions": { - "$ref": "#/components/schemas/Permissions" - }, - "account_type": { - "type": "string", - "enum": [ - "operator", - "normal" - ] - } - }, - "required": [ - "id", - "username", - "disabled", - "created_at", - "updated_at", - "permissions", - "account_type" - ] - }, - "Attributes": { - "description": "Object attributes that are modifiable only by SumUp applications.", - "type": "object", - "example": {}, - "additionalProperties": true - }, - "Address": { - "description": "An address somewhere in the world. The address fields used depend on the country conventions. For example, in Great Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addresses is `state`, whereas in Chile it's `region`.\nWhether an address is valid or not depends on whether the locally required fields are present. Fields not supported in a country will be ignored.", - "type": "object", - "properties": { - "street_address": { - "type": "array", - "items": { - "type": "string", - "description": "The first line of the address.", - "maxLength": 100 - }, - "example": [ - "Paul-Linke-Ufer 39-40", - "2. Hinterhof" - ], - "maxItems": 2 - }, - "post_code": { - "description": "The postal code (aka. zip code) of the address.\n", - "type": "string", - "example": "10999", - "maxLength": 32 - }, - "country": { - "$ref": "#/components/schemas/CountryCode" - }, - "city": { - "description": "The city of the address.\n", - "type": "string", - "example": "Berlin", - "maxLength": 512 - }, - "province": { - "description": "The province where the address is located. This may not be relevant in some countries.\n", - "type": "string", - "example": "Berlin", - "maxLength": 512 - }, - "region": { - "description": "The region where the address is located. This may not be relevant in some countries.\n", - "type": "string", - "example": "Baden Wuerttemberg", - "maxLength": 512 - }, - "county": { - "description": "A county is a geographic region of a country used for administrative or other purposes in some nations. Used in countries such as Ireland, Romania, etc.\n", - "type": "string", - "example": "Dublin County", - "maxLength": 512 - }, - "autonomous_community": { - "description": "In Spain, an autonomous community is the first sub-national level of political and administrative division.\n", - "type": "string", - "example": "Catalonia", - "maxLength": 512 - }, - "post_town": { - "description": "A post town is a required part of all postal addresses in the United Kingdom and Ireland, and a basic unit of the postal delivery system.\n", - "type": "string", - "example": "London", - "maxLength": 512 - }, - "state": { - "description": "Most often, a country has a single state, with various administrative divisions. The term \"state\" is sometimes used to refer to the federated polities that make up the federation. Used in countries such as the United States and Brazil.\n", - "type": "string", - "example": "California", - "maxLength": 512 - }, - "neighborhood": { - "description": "Locality level of the address. Used in countries such as Brazil or Chile.\n", - "type": "string", - "example": "Copacabana", - "maxLength": 512 - }, - "commune": { - "description": "In many countries, terms cognate with \"commune\" are used, referring to the community living in the area and the common interest. Used in countries such as Chile.\n", - "type": "string", - "example": "Providencia", - "maxLength": 512 - }, - "department": { - "description": "A department (French: département, Spanish: departamento) is an administrative or political division in several countries. Used in countries such as Colombia.\n", - "type": "string", - "example": "Antioquia", - "maxLength": 512 - }, - "municipality": { - "description": "A municipality is usually a single administrative division having corporate status and powers of self-government or jurisdiction as granted by national and regional laws to which it is subordinate. Used in countries such as Colombia.\n", - "type": "string", - "example": "Medellín", - "maxLength": 512 - }, - "district": { - "description": "A district is a type of administrative division that in some countries is managed by the local government. Used in countries such as Portugal.\n", - "type": "string", - "example": "Lisbon District", - "maxLength": 512 - }, - "zip_code": { - "description": "A US system of postal codes used by the United States Postal Service (USPS).\n", - "type": "string", - "example": "94103", - "maxLength": 512 - }, - "eircode": { - "description": "A postal address in Ireland.\n", - "type": "string", - "example": "D02 X285", - "maxLength": 512 - } - }, - "example": { - "street_address": [ - "Paul-Linke-Ufer 39-40", - "2. Hinterhof" - ], - "post_code": "10999", - "city": "Berlin", - "country": "DE" - }, - "externalDocs": { - "description": "Address documentation", - "url": "https://backstage.sumup.net/docs/default/Component/merchants/merchant/#addresses" - }, - "required": [ - "country" - ] + "example": "EUR", + "enum": [ + "BGN", + "BRL", + "CHF", + "CLP", + "COP", + "CZK", + "DKK", + "EUR", + "GBP", + "HRK", + "HUF", + "NOK", + "PLN", + "RON", + "SEK", + "USD" + ], + "title": "Currency" }, - "CountryCode": { - "description": "An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)\ncountry code. This definition users `oneOf` with a two-character string\ntype to allow for support of future countries in client code.", + "EventType": { + "description": "Type of the transaction event.", "type": "string", - "example": "BR", - "maxLength": 2, - "minLength": 2, - "pattern": "^[A-Z]{2}$" + "enum": [ + "PAYOUT", + "CHARGE_BACK", + "REFUND", + "PAYOUT_DEDUCTION" + ], + "title": "Event Type" }, - "PersonalIdentifier": { - "type": "object", - "properties": { - "ref": { - "description": "The unique reference for the personal identifier type.", - "type": "string", - "example": "br.cpf", - "maxLength": 32 - }, - "value": { - "description": "The company identifier value.", - "type": "string", - "example": "847.060.136-90", - "maxLength": 128 - } - }, - "example": { - "ref": "br.cpf", - "value": "847.060.136-90" - }, - "required": [ - "ref", - "value" - ] + "EventStatus": { + "description": "Status of the transaction event.\n\nNot every value is used for every event type.\n\n- `PENDING`: The event has been created but is not final yet. Used for events that are still being processed and whose final outcome is not known yet.\n- `SCHEDULED`: The event is planned for a future payout cycle but has not been executed yet. This applies to payout events before money is actually sent out.\n- `RECONCILED`: The underlying payment has been matched with settlement data and is ready to continue through payout processing, but the funds have not been paid out yet. This applies to payout events.\n- `PAID_OUT`: The payout event has been completed and the funds were included in a merchant payout.\n- `REFUNDED`: A refund event has been accepted and recorded in the refund flow. This is the status returned for refund events once the transaction amount is being or has been returned to the payer.\n- `SUCCESSFUL`: The event completed successfully. Use this as the generic terminal success status for event types that do not expose a more specific business outcome such as `PAID_OUT` or `REFUNDED`.\n- `FAILED`: The event could not be completed. Typical examples are a payout that could not be executed or an event that was rejected during processing.", + "type": "string", + "enum": [ + "FAILED", + "PAID_OUT", + "PENDING", + "RECONCILED", + "REFUNDED", + "SCHEDULED", + "SUCCESSFUL" + ], + "title": "Event Status" + }, + "EventID": { + "description": "Unique ID of the transaction event.", + "type": "integer", + "format": "int64", + "title": "Event ID" + }, + "HorizontalAccuracy": { + "description": "Indication of the precision of the geographical position received from the payment terminal.", + "type": "number", + "format": "float", + "title": "Horizontal Accuracy" + }, + "Lat": { + "description": "Latitude value from the coordinates of the payment location (as received from the payment terminal reader).", + "type": "number", + "format": "float", + "maximum": 90, + "minimum": 0, + "title": "Latitude" + }, + "Lon": { + "description": "Longitude value from the coordinates of the payment location (as received from the payment terminal reader).", + "type": "number", + "format": "float", + "maximum": 180, + "minimum": 0, + "title": "Longitude" + }, + "TransactionID": { + "description": "Unique ID of the transaction.", + "type": "string", + "title": "Transaction ID" }, "MembershipStatus": { "description": "The status of the membership.", @@ -9167,8 +8082,7 @@ "type": "string" }, "example": [], - "maxItems": 100, - "x-deprecation-notice": "Permissions include only legacy permissions, please use roles instead. Member access is based on their roles within a given resource and the permissions these roles grant." + "maxItems": 100 }, "is_predefined": { "description": "True if the role is provided by SumUp.", @@ -9201,6 +8115,12 @@ ], "title": "Role" }, + "Attributes": { + "description": "Object attributes that are modifiable only by SumUp applications.", + "type": "object", + "example": {}, + "additionalProperties": true + }, "Metadata": { "description": "Set of user-defined key-value pairs attached to the object. Partial updates are not supported. When updating, always submit whole metadata. Maximum of 64 parameters are allowed in the object.", "type": "object", @@ -9420,12 +8340,199 @@ } ] }, + "CountryCode": { + "description": "An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. This definition users `oneOf` with a two-character string type to allow for support of future countries in client code.\n", + "type": "string", + "examples": [ + "AR", + "AT", + "AU", + "BE", + "BG", + "BR", + "CH", + "CL", + "CO", + "CY", + "CZ", + "DE", + "DK", + "EE", + "ES", + "FI", + "FR", + "GB", + "GR", + "HU", + "IE", + "IT", + "LT", + "LU", + "LV", + "MT", + "MX", + "NL", + "NO", + "PE", + "PL", + "PT", + "RO", + "SE", + "SI", + "SK", + "US" + ], + "maxLength": 2, + "minLength": 2 + }, "PhoneNumber": { "description": "A publicly available phone number in [E.164](https://en.wikipedia.org/wiki/E.164) format.\n", "type": "string", "example": "+420123456789", "maxLength": 16 }, + "Address": { + "description": "An address somewhere in the world. The address fields used depend on the country conventions. For example, in Great Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addresses is `state`, whereas in Chile it's `region`.\nWhether an address is valid or not depends on whether the locally required fields are present. Fields not supported in a country will be ignored.", + "type": "object", + "properties": { + "street_address": { + "type": "array", + "items": { + "type": "string", + "description": "The first line of the address.", + "maxLength": 100 + }, + "example": [ + "Paul-Linke-Ufer 39-40", + "2. Hinterhof" + ], + "maxItems": 2, + "minItems": 1 + }, + "post_code": { + "description": "The postal code (aka. zip code) of the address.\n", + "type": "string", + "example": "10999", + "maxLength": 10 + }, + "country": { + "$ref": "#/components/schemas/CountryCode" + }, + "city": { + "description": "The city of the address.\n", + "type": "string", + "example": "Berlin", + "maxLength": 60 + }, + "province": { + "description": "The province where the address is located. This may not be relevant in some countries.\n", + "type": "string", + "example": "Ontario", + "maxLength": 60 + }, + "region": { + "description": "The region where the address is located. This may not be relevant in some countries.\n", + "type": "string", + "example": "Baden-Wuerttemberg", + "maxLength": 60 + }, + "county": { + "description": "A county is a geographic region of a country used for administrative or other purposes in some nations. Used in countries such as Ireland, Romania, etc.\n", + "type": "string", + "example": "Dublin", + "maxLength": 60 + }, + "autonomous_community": { + "description": "In Spain, an autonomous community is the first sub-national level of political and administrative division.\n", + "type": "string", + "example": "Catalonia", + "maxLength": 60 + }, + "post_town": { + "description": "A post town is a required part of all postal addresses in the United Kingdom and Ireland, and a basic unit of the postal delivery system.\n", + "type": "string", + "example": "London", + "maxLength": 60 + }, + "state": { + "description": "Most often, a country has a single state, with various administrative divisions. The term \"state\" is sometimes used to refer to the federated polities that make up the federation. Used in countries such as the United States and Brazil.\n", + "type": "string", + "example": "California", + "maxLength": 60 + }, + "neighborhood": { + "description": "Locality level of the address. Used in countries such as Brazil or Chile.\n", + "type": "string", + "example": "Copacabana", + "maxLength": 60 + }, + "commune": { + "description": "In many countries, terms cognate with \"commune\" are used, referring to the community living in the area and the common interest. Used in countries such as Chile.\n", + "type": "string", + "example": "Providencia", + "maxLength": 60 + }, + "department": { + "description": "A department (French: département, Spanish: departamento) is an administrative or political division in several countries. Used in countries such as Colombia.\n", + "type": "string", + "example": "Antioquia", + "maxLength": 60 + }, + "municipality": { + "description": "A municipality is usually a single administrative division having corporate status and powers of self-government or jurisdiction as granted by national and regional laws to which it is subordinate. Used in countries such as Colombia.\n", + "type": "string", + "example": "Medellin", + "maxLength": 60 + }, + "district": { + "description": "A district is a type of administrative division that in some countries is managed by the local government. Used in countries such as Portugal.\n", + "type": "string", + "example": "Lisbon", + "maxLength": 60 + }, + "zip_code": { + "description": "A US system of postal codes used by the United States Postal Service (USPS).\n", + "type": "string", + "example": "94103", + "maxLength": 10 + }, + "eircode": { + "description": "A postal address in Ireland.\n", + "type": "string", + "example": "D02 X285", + "maxLength": 10 + } + }, + "examples": [ + { + "street_address": [ + "Paul-Linke-Ufer 39-40", + "2. Hinterhof" + ], + "post_code": "10999", + "city": "Berlin", + "country": "DE" + }, + { + "street_address": [ + "156 Avenida Vida Nova", + "Apto 2" + ], + "city": "Taboão da Serra", + "post_code": "06764045", + "state": "SP", + "neighborhood": "Jardim Maria Rosa", + "country": "BR" + } + ], + "externalDocs": { + "description": "Address documentation", + "url": "https://developer.sumup.com/tools/glossary/merchant#addresses" + }, + "required": [ + "country" + ] + }, "Branding": { "description": "Settings used to apply the Merchant's branding to email receipts, invoices, checkouts, and other products.", "type": "object", @@ -9565,6 +8672,36 @@ "share" ] }, + "PersonalIdentifier": { + "type": "object", + "properties": { + "ref": { + "description": "The unique reference for the personal identifier type as defined in the country SDK.\n", + "type": "string", + "examples": [ + "br.cpf" + ] + }, + "value": { + "description": "The company identifier value.\n", + "type": "string", + "examples": [ + "847.060.136-90" + ], + "maxLength": 30 + } + }, + "examples": [ + { + "ref": "br.cpf", + "value": "847.060.136-90" + } + ], + "required": [ + "ref", + "value" + ] + }, "Version": { "description": "The version of the resource. The version reflects a specific change submitted to the API via one of the `PATCH` endpoints.\n", "type": "string", @@ -11315,16 +10452,6 @@ } ] }, - { - "name": "Subaccounts", - "description": "Endpoints for managing merchant sub-accounts (operators).", - "x-deprecation-notice": "Subaccounts API is deprecated, please use [Members](https://developer.sumup.com/api/members) API instead to manage your account members.", - "x-core-objects": [ - { - "$ref": "#/components/schemas/Operator" - } - ] - }, { "name": "Members", "description": "Endpoints to manage account members. Members are users that have membership within merchant accounts.", diff --git a/sumup/_client.py b/sumup/_client.py index 078f6ce..6fc4bfb 100644 --- a/sumup/_client.py +++ b/sumup/_client.py @@ -13,7 +13,6 @@ from .readers import ReadersResource, AsyncReadersResource from .receipts import ReceiptsResource, AsyncReceiptsResource from .roles import RolesResource, AsyncRolesResource -from .subaccounts import SubaccountsResource, AsyncSubaccountsResource from .transactions import TransactionsResource, AsyncTransactionsResource BASE_URL = "https://api.sumup.com" @@ -113,13 +112,6 @@ def roles(self) -> RolesResource: return RolesResource(self._client) - @property - def subaccounts(self) -> SubaccountsResource: - """Access the Subaccounts API endpoints.""" - from .subaccounts.resource import SubaccountsResource - - return SubaccountsResource(self._client) - @property def transactions(self) -> TransactionsResource: """Access the Transactions API endpoints.""" @@ -212,13 +204,6 @@ def roles(self) -> AsyncRolesResource: return AsyncRolesResource(self._client) - @property - def subaccounts(self) -> AsyncSubaccountsResource: - """Access the Subaccounts API endpoints.""" - from .subaccounts.resource import AsyncSubaccountsResource - - return AsyncSubaccountsResource(self._client) - @property def transactions(self) -> AsyncTransactionsResource: """Access the Transactions API endpoints.""" diff --git a/sumup/payouts/__init__.py b/sumup/payouts/__init__.py index 246a830..9a7c283 100755 --- a/sumup/payouts/__init__.py +++ b/sumup/payouts/__init__.py @@ -6,6 +6,7 @@ from ..types import ( Error, ErrorExtended, + FinancialPayout, FinancialPayouts, Problem, ) @@ -16,6 +17,7 @@ "AsyncPayoutsResource", "Error", "ErrorExtended", + "FinancialPayout", "FinancialPayouts", "Problem", ] diff --git a/sumup/payouts/resource.py b/sumup/payouts/resource.py index 8e033d7..8d18b3b 100755 --- a/sumup/payouts/resource.py +++ b/sumup/payouts/resource.py @@ -17,7 +17,7 @@ serialize_request_data, ) from .._exceptions import APIError -from ..types import Error, ErrorExtended, FinancialPayouts, Problem +from ..types import Error, ErrorExtended, FinancialPayout, FinancialPayouts, Problem import datetime import httpx import typing @@ -28,10 +28,6 @@ ListPayoutsV1ParamsOrderInput = typing.Union[typing.Literal["asc", "desc"], str] -ListPayoutsParamsFormatInput = typing.Union[typing.Literal["csv", "json"], str] - -ListPayoutsParamsOrderInput = typing.Union[typing.Literal["asc", "desc"], str] - class PayoutsResource(Resource): """API resource for the Payouts endpoints.""" @@ -53,53 +49,13 @@ def list( """ List payouts - Lists ordered payouts for the merchant account. - """ - query_data: dict[str, typing.Any] = {} - query_data["start_date"] = start_date - query_data["end_date"] = end_date - if not isinstance(format, NotGivenType) and format is not None: - query_data["format"] = format - if not isinstance(limit, NotGivenType) and limit is not None: - query_data["limit"] = limit - if not isinstance(order, NotGivenType) and order is not None: - query_data["order"] = order + Lists payout and payout-deduction records for the specified merchant account within the requested date range. - resp = self._client.get( - f"/v1.0/merchants/{merchant_code}/payouts", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(FinancialPayouts).validate_python(resp.json()) - elif resp.status_code == 400: - raise APIError( - "The request is invalid for the submitted query parameters.", - status=resp.status_code, - body=resp.text, - ) - elif resp.status_code == 401: - raise APIError( - "The request is not authorized.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated("This method is deprecated") - def list_deprecated( - self, - *, - start_date: datetime.date, - end_date: datetime.date, - format: typing.Union[ListPayoutsParamsFormatInput, NotGivenType] = NOT_GIVEN, - limit: typing.Union[int, NotGivenType] = NOT_GIVEN, - order: typing.Union[ListPayoutsParamsOrderInput, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> FinancialPayouts: - """ - List payouts + The response can include: + - regular payouts (`type = PAYOUT`) + - deduction records for refunds, chargebacks, direct debit returns, or balance adjustments - Lists ordered payouts for the merchant account. + Results are sorted by payout date in the requested `order`. """ query_data: dict[str, typing.Any] = {} query_data["start_date"] = start_date @@ -112,7 +68,7 @@ def list_deprecated( query_data["order"] = order resp = self._client.get( - f"/v0.1/me/financials/payouts", + f"/v1.0/merchants/{merchant_code}/payouts", params=serialize_query_params(query_data) if query_data else None, headers=headers, ) @@ -152,53 +108,13 @@ async def list( """ List payouts - Lists ordered payouts for the merchant account. - """ - query_data: dict[str, typing.Any] = {} - query_data["start_date"] = start_date - query_data["end_date"] = end_date - if not isinstance(format, NotGivenType) and format is not None: - query_data["format"] = format - if not isinstance(limit, NotGivenType) and limit is not None: - query_data["limit"] = limit - if not isinstance(order, NotGivenType) and order is not None: - query_data["order"] = order + Lists payout and payout-deduction records for the specified merchant account within the requested date range. - resp = await self._client.get( - f"/v1.0/merchants/{merchant_code}/payouts", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(FinancialPayouts).validate_python(resp.json()) - elif resp.status_code == 400: - raise APIError( - "The request is invalid for the submitted query parameters.", - status=resp.status_code, - body=resp.text, - ) - elif resp.status_code == 401: - raise APIError( - "The request is not authorized.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated("This method is deprecated") - async def list_deprecated( - self, - *, - start_date: datetime.date, - end_date: datetime.date, - format: typing.Union[ListPayoutsParamsFormatInput, NotGivenType] = NOT_GIVEN, - limit: typing.Union[int, NotGivenType] = NOT_GIVEN, - order: typing.Union[ListPayoutsParamsOrderInput, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> FinancialPayouts: - """ - List payouts + The response can include: + - regular payouts (`type = PAYOUT`) + - deduction records for refunds, chargebacks, direct debit returns, or balance adjustments - Lists ordered payouts for the merchant account. + Results are sorted by payout date in the requested `order`. """ query_data: dict[str, typing.Any] = {} query_data["start_date"] = start_date @@ -211,7 +127,7 @@ async def list_deprecated( query_data["order"] = order resp = await self._client.get( - f"/v0.1/me/financials/payouts", + f"/v1.0/merchants/{merchant_code}/payouts", params=serialize_query_params(query_data) if query_data else None, headers=headers, ) diff --git a/sumup/subaccounts/__init__.py b/sumup/subaccounts/__init__.py deleted file mode 100755 index e2fd288..0000000 --- a/sumup/subaccounts/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Code generated by `py-sdk-gen`. DO NOT EDIT. -from .resource import ( - SubaccountsResource, - AsyncSubaccountsResource, -) -from ..types import ( - Operator, - Permissions, - Problem, -) - - -__all__ = [ - "SubaccountsResource", - "AsyncSubaccountsResource", - "Operator", - "Permissions", - "Problem", -] diff --git a/sumup/subaccounts/resource.py b/sumup/subaccounts/resource.py deleted file mode 100755 index aaebe24..0000000 --- a/sumup/subaccounts/resource.py +++ /dev/null @@ -1,402 +0,0 @@ -# Code generated by `py-sdk-gen`. DO NOT EDIT. -# ruff: noqa: F401, F541 -""" -Endpoints for managing merchant sub-accounts (operators). -""" - -from __future__ import annotations -from .._service import ( - Resource, - AsyncResource, - HeaderTypes, - NotGivenType, - NOT_GIVEN, - serialize_query_params, - serialize_request_data, -) -from .._exceptions import APIError -from ..types import Operator, Permissions, Problem -import datetime -import httpx -import typing -import pydantic -import typing_extensions - - -class CreateSubAccountBodyPermissionsInput(typing_extensions.TypedDict, total=False): - """ - CreateSubAccountBodyPermissions is a schema definition. - """ - - create_moto_payments: typing_extensions.NotRequired[bool] - create_referral: typing_extensions.NotRequired[bool] - full_transaction_history_view: typing_extensions.NotRequired[bool] - refund_transactions: typing_extensions.NotRequired[bool] - - -class CreateSubAccountBodyInput(typing_extensions.TypedDict, total=False): - """ - CreateSubAccountBody is a schema definition. - """ - - password: typing_extensions.Required[ - typing_extensions.Annotated[str, typing_extensions.Doc("Min length: 8")] - ] - username: typing_extensions.Required[ - typing_extensions.Annotated[str, typing_extensions.Doc("Format: email")] - ] - nickname: typing_extensions.NotRequired[str] - permissions: typing_extensions.NotRequired[CreateSubAccountBodyPermissionsInput] - - -class UpdateSubAccountBodyPermissionsInput(typing_extensions.TypedDict, total=False): - """ - UpdateSubAccountBodyPermissions is a schema definition. - """ - - create_moto_payments: typing_extensions.NotRequired[bool] - create_referral: typing_extensions.NotRequired[bool] - full_transaction_history_view: typing_extensions.NotRequired[bool] - refund_transactions: typing_extensions.NotRequired[bool] - - -class UpdateSubAccountBodyInput(typing_extensions.TypedDict, total=False): - """ - UpdateSubAccountBody is a schema definition. - """ - - disabled: typing_extensions.NotRequired[bool] - nickname: typing_extensions.NotRequired[str] - password: typing_extensions.NotRequired[ - typing_extensions.Annotated[str, typing_extensions.Doc("Min length: 8")] - ] - permissions: typing_extensions.NotRequired[UpdateSubAccountBodyPermissionsInput] - username: typing_extensions.NotRequired[ - typing_extensions.Annotated[str, typing_extensions.Doc("Format: email\nMax length: 256")] - ] - - -ListSubAccounts200Response = list[Operator] -""" -ListSubAccounts200Response is a schema definition. -""" - - -class SubaccountsResource(Resource): - """API resource for the Subaccounts endpoints.""" - - def __init__(self, client: httpx.Client) -> None: - super().__init__(client) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to list users in your merchant account please use [List members](https://developer.sumup.com/api/members/list) instead." - ) - def list_sub_accounts( - self, - *, - query: typing.Union[str, NotGivenType] = NOT_GIVEN, - include_primary: typing.Union[bool, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> ListSubAccounts200Response: - """ - List operators - - Returns list of operators for currently authorized user's merchant. - """ - query_data: dict[str, typing.Any] = {} - if not isinstance(query, NotGivenType) and query is not None: - query_data["query"] = query - if not isinstance(include_primary, NotGivenType) and include_primary is not None: - query_data["include_primary"] = include_primary - - resp = self._client.get( - f"/v0.1/me/accounts", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(ListSubAccounts200Response).validate_python(resp.json()) - elif resp.status_code == 401: - raise APIError( - "Authentication failed or missing required scope.", - status=resp.status_code, - body=resp.text, - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to create a user in your merchant account please use [Create member](https://developer.sumup.com/api/members/create) instead." - ) - def create_sub_account( - self, - *, - username: str, - password: str, - nickname: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - permissions: typing.Union[ - CreateSubAccountBodyPermissionsInput, None, NotGivenType - ] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> Operator: - """ - Create an operator - - Creates new operator for currently authorized users' merchant. - """ - body_data: dict[str, typing.Any] = {} - body_data["username"] = username - body_data["password"] = password - if not isinstance(nickname, NotGivenType): - body_data["nickname"] = nickname - if not isinstance(permissions, NotGivenType): - body_data["permissions"] = permissions - - resp = self._client.post( - f"/v0.1/me/accounts", - json=serialize_request_data(body_data), - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(Operator).validate_python(resp.json()) - elif resp.status_code == 403: - raise APIError( - "Operator creation was forbidden.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to get a user that's a member of your merchant account please use [Get member](https://developer.sumup.com/api/members/get) instead." - ) - def compat_get_operator( - self, operator_id: int, headers: typing.Optional[HeaderTypes] = None - ) -> Operator: - """ - Retrieve an operator - - Returns specific operator. - """ - resp = self._client.get( - f"/v0.1/me/accounts/{operator_id}", - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(Operator).validate_python(resp.json()) - elif resp.status_code == 401: - raise APIError( - "Authentication failed or missing required scope.", - status=resp.status_code, - body=resp.text, - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to update a user that's a member of your merchant account please use [Update member](https://developer.sumup.com/api/members/update) instead." - ) - def update_sub_account( - self, - operator_id: int, - *, - password: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - username: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - disabled: typing.Union[bool, None, NotGivenType] = NOT_GIVEN, - nickname: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - permissions: typing.Union[ - UpdateSubAccountBodyPermissionsInput, None, NotGivenType - ] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> Operator: - """ - Update an operator - - Updates operator. If the operator was disabled and their password is updated they will be unblocked. - """ - body_data: dict[str, typing.Any] = {} - if not isinstance(password, NotGivenType): - body_data["password"] = password - if not isinstance(username, NotGivenType): - body_data["username"] = username - if not isinstance(disabled, NotGivenType): - body_data["disabled"] = disabled - if not isinstance(nickname, NotGivenType): - body_data["nickname"] = nickname - if not isinstance(permissions, NotGivenType): - body_data["permissions"] = permissions - - resp = self._client.put( - f"/v0.1/me/accounts/{operator_id}", - json=serialize_request_data(body_data), - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(Operator).validate_python(resp.json()) - elif resp.status_code == 400: - raise APIError( - "Invalid Operators' email or password was already used.", - status=resp.status_code, - body=resp.text, - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - -class AsyncSubaccountsResource(AsyncResource): - """Async API resource for the Subaccounts endpoints.""" - - def __init__(self, client: httpx.AsyncClient) -> None: - super().__init__(client) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to list users in your merchant account please use [List members](https://developer.sumup.com/api/members/list) instead." - ) - async def list_sub_accounts( - self, - *, - query: typing.Union[str, NotGivenType] = NOT_GIVEN, - include_primary: typing.Union[bool, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> ListSubAccounts200Response: - """ - List operators - - Returns list of operators for currently authorized user's merchant. - """ - query_data: dict[str, typing.Any] = {} - if not isinstance(query, NotGivenType) and query is not None: - query_data["query"] = query - if not isinstance(include_primary, NotGivenType) and include_primary is not None: - query_data["include_primary"] = include_primary - - resp = await self._client.get( - f"/v0.1/me/accounts", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(ListSubAccounts200Response).validate_python(resp.json()) - elif resp.status_code == 401: - raise APIError( - "Authentication failed or missing required scope.", - status=resp.status_code, - body=resp.text, - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to create a user in your merchant account please use [Create member](https://developer.sumup.com/api/members/create) instead." - ) - async def create_sub_account( - self, - *, - username: str, - password: str, - nickname: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - permissions: typing.Union[ - CreateSubAccountBodyPermissionsInput, None, NotGivenType - ] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> Operator: - """ - Create an operator - - Creates new operator for currently authorized users' merchant. - """ - body_data: dict[str, typing.Any] = {} - body_data["username"] = username - body_data["password"] = password - if not isinstance(nickname, NotGivenType): - body_data["nickname"] = nickname - if not isinstance(permissions, NotGivenType): - body_data["permissions"] = permissions - - resp = await self._client.post( - f"/v0.1/me/accounts", - json=serialize_request_data(body_data), - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(Operator).validate_python(resp.json()) - elif resp.status_code == 403: - raise APIError( - "Operator creation was forbidden.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to get a user that's a member of your merchant account please use [Get member](https://developer.sumup.com/api/members/get) instead." - ) - async def compat_get_operator( - self, operator_id: int, headers: typing.Optional[HeaderTypes] = None - ) -> Operator: - """ - Retrieve an operator - - Returns specific operator. - """ - resp = await self._client.get( - f"/v0.1/me/accounts/{operator_id}", - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(Operator).validate_python(resp.json()) - elif resp.status_code == 401: - raise APIError( - "Authentication failed or missing required scope.", - status=resp.status_code, - body=resp.text, - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated( - "Subaccounts API is deprecated, to update a user that's a member of your merchant account please use [Update member](https://developer.sumup.com/api/members/update) instead." - ) - async def update_sub_account( - self, - operator_id: int, - *, - password: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - username: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - disabled: typing.Union[bool, None, NotGivenType] = NOT_GIVEN, - nickname: typing.Union[str, None, NotGivenType] = NOT_GIVEN, - permissions: typing.Union[ - UpdateSubAccountBodyPermissionsInput, None, NotGivenType - ] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> Operator: - """ - Update an operator - - Updates operator. If the operator was disabled and their password is updated they will be unblocked. - """ - body_data: dict[str, typing.Any] = {} - if not isinstance(password, NotGivenType): - body_data["password"] = password - if not isinstance(username, NotGivenType): - body_data["username"] = username - if not isinstance(disabled, NotGivenType): - body_data["disabled"] = disabled - if not isinstance(nickname, NotGivenType): - body_data["nickname"] = nickname - if not isinstance(permissions, NotGivenType): - body_data["permissions"] = permissions - - resp = await self._client.put( - f"/v0.1/me/accounts/{operator_id}", - json=serialize_request_data(body_data), - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(Operator).validate_python(resp.json()) - elif resp.status_code == 400: - raise APIError( - "Invalid Operators' email or password was already used.", - status=resp.status_code, - body=resp.text, - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) diff --git a/sumup/transactions/__init__.py b/sumup/transactions/__init__.py index d298256..f369ed5 100755 --- a/sumup/transactions/__init__.py +++ b/sumup/transactions/__init__.py @@ -3,7 +3,6 @@ TransactionsResource, AsyncTransactionsResource, ListTransactionsV21200Response, - ListTransactions200Response, ) from ..types import ( CardResponse, @@ -39,7 +38,6 @@ "TransactionsResource", "AsyncTransactionsResource", "ListTransactionsV21200Response", - "ListTransactions200Response", "CardResponse", "CardType", "Currency", diff --git a/sumup/transactions/resource.py b/sumup/transactions/resource.py index 6b80c43..1000cfa 100755 --- a/sumup/transactions/resource.py +++ b/sumup/transactions/resource.py @@ -93,16 +93,6 @@ class RefundTransactionBodyInput(typing_extensions.TypedDict, total=False): typing.Literal["CHARGE_BACK", "PAYMENT", "REFUND"], str ] -ListTransactionsParamsOrderInput = typing.Union[typing.Literal["ascending", "descending"], str] - -ListTransactionsParamsStatuseInput = typing.Union[ - typing.Literal["CANCELLED", "CHARGE_BACK", "FAILED", "REFUNDED", "SUCCESSFUL"], str -] - -ListTransactionsParamsTypeInput = typing.Union[ - typing.Literal["CHARGE_BACK", "PAYMENT", "REFUND"], str -] - class ListTransactionsV21200Response(pydantic.BaseModel): """ @@ -114,16 +104,6 @@ class ListTransactionsV21200Response(pydantic.BaseModel): links: typing.Optional[list[TransactionsHistoryLink]] = None -class ListTransactions200Response(pydantic.BaseModel): - """ - ListTransactions200Response is a schema definition. - """ - - items: typing.Optional[list[TransactionHistory]] = None - - links: typing.Optional[list[TransactionsHistoryLink]] = None - - class TransactionsResource(Resource): """API resource for the Transactions endpoints.""" @@ -132,7 +112,8 @@ def __init__(self, client: httpx.Client) -> None: def refund( self, - txn_id: str, + merchant_code: str, + id: str, *, amount: typing.Union[float, None, NotGivenType] = NOT_GIVEN, headers: typing.Optional[HeaderTypes] = None, @@ -147,7 +128,7 @@ def refund( body_data["amount"] = amount resp = self._client.post( - f"/v0.1/me/refund/{txn_id}", + f"/v1.0/merchants/{merchant_code}/payments/{id}/refunds", json=serialize_request_data(body_data), headers=headers, ) @@ -219,47 +200,6 @@ def get( else: raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - @typing_extensions.deprecated("This method is deprecated") - def get_deprecated( - self, - *, - id: typing.Union[str, NotGivenType] = NOT_GIVEN, - transaction_code: typing.Union[str, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> TransactionFull: - """ - Retrieve a transaction - - Retrieves the full details of an identified transaction. The transaction resource is identified by a query parameter and*one* of following parameters is required: - - `id` - - `transaction_code` - - `foreign_transaction_id` - - `client_transaction_id` - """ - query_data: dict[str, typing.Any] = {} - if not isinstance(id, NotGivenType) and id is not None: - query_data["id"] = id - if not isinstance(transaction_code, NotGivenType) and transaction_code is not None: - query_data["transaction_code"] = transaction_code - - resp = self._client.get( - f"/v0.1/me/transactions", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(TransactionFull).validate_python(resp.json()) - elif resp.status_code == 401: - raise APIError( - "The request is not authorized.", status=resp.status_code, body=resp.text - ) - elif resp.status_code == 404: - raise APIError( - "The requested resource does not exist.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - def list( self, merchant_code: str, @@ -336,79 +276,6 @@ def list( else: raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - @typing_extensions.deprecated("This method is deprecated") - def list_deprecated( - self, - *, - transaction_code: typing.Union[str, NotGivenType] = NOT_GIVEN, - order: typing.Union[ListTransactionsParamsOrderInput, NotGivenType] = NOT_GIVEN, - limit: typing.Union[int, NotGivenType] = NOT_GIVEN, - users: typing.Union[typing.Sequence[str], NotGivenType] = NOT_GIVEN, - statuses: typing.Union[ - typing.Sequence[ListTransactionsParamsStatuseInput], NotGivenType - ] = NOT_GIVEN, - payment_types: typing.Union[typing.Sequence[PaymentTypeInput], NotGivenType] = NOT_GIVEN, - types: typing.Union[ - typing.Sequence[ListTransactionsParamsTypeInput], NotGivenType - ] = NOT_GIVEN, - changes_since: typing.Union[datetime.datetime, NotGivenType] = NOT_GIVEN, - newest_time: typing.Union[datetime.datetime, NotGivenType] = NOT_GIVEN, - newest_ref: typing.Union[str, NotGivenType] = NOT_GIVEN, - oldest_time: typing.Union[datetime.datetime, NotGivenType] = NOT_GIVEN, - oldest_ref: typing.Union[str, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> ListTransactions200Response: - """ - List transactions - - Lists detailed history of all transactions associated with the merchant profile. - """ - query_data: dict[str, typing.Any] = {} - if not isinstance(transaction_code, NotGivenType) and transaction_code is not None: - query_data["transaction_code"] = transaction_code - if not isinstance(order, NotGivenType) and order is not None: - query_data["order"] = order - if not isinstance(limit, NotGivenType) and limit is not None: - query_data["limit"] = limit - if not isinstance(users, NotGivenType) and users is not None: - query_data["users"] = list(users) - if not isinstance(statuses, NotGivenType) and statuses is not None: - query_data["statuses[]"] = list(statuses) - if not isinstance(payment_types, NotGivenType) and payment_types is not None: - query_data["payment_types"] = list(payment_types) - if not isinstance(types, NotGivenType) and types is not None: - query_data["types"] = list(types) - if not isinstance(changes_since, NotGivenType) and changes_since is not None: - query_data["changes_since"] = changes_since - if not isinstance(newest_time, NotGivenType) and newest_time is not None: - query_data["newest_time"] = newest_time - if not isinstance(newest_ref, NotGivenType) and newest_ref is not None: - query_data["newest_ref"] = newest_ref - if not isinstance(oldest_time, NotGivenType) and oldest_time is not None: - query_data["oldest_time"] = oldest_time - if not isinstance(oldest_ref, NotGivenType) and oldest_ref is not None: - query_data["oldest_ref"] = oldest_ref - - resp = self._client.get( - f"/v0.1/me/transactions/history", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(ListTransactions200Response).validate_python(resp.json()) - elif resp.status_code == 400: - raise APIError( - "The request is invalid for the submitted query parameters.", - status=resp.status_code, - body=resp.text, - ) - elif resp.status_code == 401: - raise APIError( - "The request is not authorized.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - class AsyncTransactionsResource(AsyncResource): """Async API resource for the Transactions endpoints.""" @@ -418,7 +285,8 @@ def __init__(self, client: httpx.AsyncClient) -> None: async def refund( self, - txn_id: str, + merchant_code: str, + id: str, *, amount: typing.Union[float, None, NotGivenType] = NOT_GIVEN, headers: typing.Optional[HeaderTypes] = None, @@ -433,7 +301,7 @@ async def refund( body_data["amount"] = amount resp = await self._client.post( - f"/v0.1/me/refund/{txn_id}", + f"/v1.0/merchants/{merchant_code}/payments/{id}/refunds", json=serialize_request_data(body_data), headers=headers, ) @@ -505,47 +373,6 @@ async def get( else: raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - @typing_extensions.deprecated("This method is deprecated") - async def get_deprecated( - self, - *, - id: typing.Union[str, NotGivenType] = NOT_GIVEN, - transaction_code: typing.Union[str, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> TransactionFull: - """ - Retrieve a transaction - - Retrieves the full details of an identified transaction. The transaction resource is identified by a query parameter and*one* of following parameters is required: - - `id` - - `transaction_code` - - `foreign_transaction_id` - - `client_transaction_id` - """ - query_data: dict[str, typing.Any] = {} - if not isinstance(id, NotGivenType) and id is not None: - query_data["id"] = id - if not isinstance(transaction_code, NotGivenType) and transaction_code is not None: - query_data["transaction_code"] = transaction_code - - resp = await self._client.get( - f"/v0.1/me/transactions", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(TransactionFull).validate_python(resp.json()) - elif resp.status_code == 401: - raise APIError( - "The request is not authorized.", status=resp.status_code, body=resp.text - ) - elif resp.status_code == 404: - raise APIError( - "The requested resource does not exist.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - async def list( self, merchant_code: str, @@ -621,76 +448,3 @@ async def list( ) else: raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) - - @typing_extensions.deprecated("This method is deprecated") - async def list_deprecated( - self, - *, - transaction_code: typing.Union[str, NotGivenType] = NOT_GIVEN, - order: typing.Union[ListTransactionsParamsOrderInput, NotGivenType] = NOT_GIVEN, - limit: typing.Union[int, NotGivenType] = NOT_GIVEN, - users: typing.Union[typing.Sequence[str], NotGivenType] = NOT_GIVEN, - statuses: typing.Union[ - typing.Sequence[ListTransactionsParamsStatuseInput], NotGivenType - ] = NOT_GIVEN, - payment_types: typing.Union[typing.Sequence[PaymentTypeInput], NotGivenType] = NOT_GIVEN, - types: typing.Union[ - typing.Sequence[ListTransactionsParamsTypeInput], NotGivenType - ] = NOT_GIVEN, - changes_since: typing.Union[datetime.datetime, NotGivenType] = NOT_GIVEN, - newest_time: typing.Union[datetime.datetime, NotGivenType] = NOT_GIVEN, - newest_ref: typing.Union[str, NotGivenType] = NOT_GIVEN, - oldest_time: typing.Union[datetime.datetime, NotGivenType] = NOT_GIVEN, - oldest_ref: typing.Union[str, NotGivenType] = NOT_GIVEN, - headers: typing.Optional[HeaderTypes] = None, - ) -> ListTransactions200Response: - """ - List transactions - - Lists detailed history of all transactions associated with the merchant profile. - """ - query_data: dict[str, typing.Any] = {} - if not isinstance(transaction_code, NotGivenType) and transaction_code is not None: - query_data["transaction_code"] = transaction_code - if not isinstance(order, NotGivenType) and order is not None: - query_data["order"] = order - if not isinstance(limit, NotGivenType) and limit is not None: - query_data["limit"] = limit - if not isinstance(users, NotGivenType) and users is not None: - query_data["users"] = list(users) - if not isinstance(statuses, NotGivenType) and statuses is not None: - query_data["statuses[]"] = list(statuses) - if not isinstance(payment_types, NotGivenType) and payment_types is not None: - query_data["payment_types"] = list(payment_types) - if not isinstance(types, NotGivenType) and types is not None: - query_data["types"] = list(types) - if not isinstance(changes_since, NotGivenType) and changes_since is not None: - query_data["changes_since"] = changes_since - if not isinstance(newest_time, NotGivenType) and newest_time is not None: - query_data["newest_time"] = newest_time - if not isinstance(newest_ref, NotGivenType) and newest_ref is not None: - query_data["newest_ref"] = newest_ref - if not isinstance(oldest_time, NotGivenType) and oldest_time is not None: - query_data["oldest_time"] = oldest_time - if not isinstance(oldest_ref, NotGivenType) and oldest_ref is not None: - query_data["oldest_ref"] = oldest_ref - - resp = await self._client.get( - f"/v0.1/me/transactions/history", - params=serialize_query_params(query_data) if query_data else None, - headers=headers, - ) - if resp.status_code == 200: - return pydantic.TypeAdapter(ListTransactions200Response).validate_python(resp.json()) - elif resp.status_code == 400: - raise APIError( - "The request is invalid for the submitted query parameters.", - status=resp.status_code, - body=resp.text, - ) - elif resp.status_code == 401: - raise APIError( - "The request is not authorized.", status=resp.status_code, body=resp.text - ) - else: - raise APIError(f"Unexpected response", status=resp.status_code, body=resp.text) diff --git a/sumup/types/__init__.py b/sumup/types/__init__.py index 87a95d7..b7da03e 100755 --- a/sumup/types/__init__.py +++ b/sumup/types/__init__.py @@ -7,12 +7,10 @@ CountryCode = str """ -An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) -country code. This definition users `oneOf` with a two-character string -type to allow for support of future countries in client code. +An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. This definition users`oneOf` with a two-character string type to allow for support of future countries in client code. + Min length: 2 Max length: 2 -Pattern: ^[A-Z]{2}$ """ @@ -20,112 +18,110 @@ class Address(pydantic.BaseModel): """ An address somewhere in the world. The address fields used depend on the country conventions. For example, inGreat Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addressesis `state`, whereas in Chile it's `region`. Whether an address is valid or not depends on whether the locally required fields are present. Fields not supported ina country will be ignored. - Address documentation: https://backstage.sumup.net/docs/default/Component/merchants/merchant/#addresses + Address documentation: https://developer.sumup.com/tools/glossary/merchant#addresses """ country: CountryCode """ - An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - country code. This definition users `oneOf` with a two-character string - type to allow for support of future countries in client code. + An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. This definition users`oneOf` with a two-character string type to allow for support of future countries in client code. Min length: 2 Max length: 2 - Pattern: ^[A-Z]{2}$ """ autonomous_community: typing.Optional[str] = None """ In Spain, an autonomous community is the first sub-national level of political and administrative division. - Max length: 512 + Max length: 60 """ city: typing.Optional[str] = None """ The city of the address. - Max length: 512 + Max length: 60 """ commune: typing.Optional[str] = None """ In many countries, terms cognate with "commune" are used, referring to the community living in the area andthe common interest. Used in countries such as Chile. - Max length: 512 + Max length: 60 """ county: typing.Optional[str] = None """ A county is a geographic region of a country used for administrative or other purposes in some nations. Usedin countries such as Ireland, Romania, etc. - Max length: 512 + Max length: 60 """ department: typing.Optional[str] = None """ A department (French: département, Spanish: departamento) is an administrative or political division inseveral countries. Used in countries such as Colombia. - Max length: 512 + Max length: 60 """ district: typing.Optional[str] = None """ A district is a type of administrative division that in some countries is managed by the local government. Usedin countries such as Portugal. - Max length: 512 + Max length: 60 """ eircode: typing.Optional[str] = None """ A postal address in Ireland. - Max length: 512 + Max length: 10 """ municipality: typing.Optional[str] = None """ A municipality is usually a single administrative division having corporate status and powers of self-government orjurisdiction as granted by national and regional laws to which it is subordinate. Used in countries such asColombia. - Max length: 512 + Max length: 60 """ neighborhood: typing.Optional[str] = None """ Locality level of the address. Used in countries such as Brazil or Chile. - Max length: 512 + Max length: 60 """ post_code: typing.Optional[str] = None """ The postal code (aka. zip code) of the address. - Max length: 32 + Max length: 10 """ post_town: typing.Optional[str] = None """ A post town is a required part of all postal addresses in the United Kingdom and Ireland, and a basic unitof the postal delivery system. - Max length: 512 + Max length: 60 """ province: typing.Optional[str] = None """ The province where the address is located. This may not be relevant in some countries. - Max length: 512 + Max length: 60 """ region: typing.Optional[str] = None """ The region where the address is located. This may not be relevant in some countries. - Max length: 512 + Max length: 60 """ state: typing.Optional[str] = None """ Most often, a country has a single state, with various administrative divisions. The term "state" is sometimesused to refer to the federated polities that make up the federation. Used in countries such as the United Statesand Brazil. - Max length: 512 + Max length: 60 """ street_address: typing.Optional[list[str]] = None """ + Min items: 1 Max items: 2 """ zip_code: typing.Optional[str] = None """ A US system of postal codes used by the United States Postal Service (USPS). - Max length: 512 + Max length: 10 """ @@ -277,14 +273,13 @@ class PersonalIdentifier(pydantic.BaseModel): ref: str """ - The unique reference for the personal identifier type. - Max length: 32 + The unique reference for the personal identifier type as defined in the country SDK. """ value: str """ The company identifier value. - Max length: 128 + Max length: 30 """ @@ -318,7 +313,7 @@ class BasePerson(pydantic.BaseModel): """ An address somewhere in the world. The address fields used depend on the country conventions. For example, inGreat Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addressesis `state`, whereas in Chile it's `region`. Whether an address is valid or not depends on whether the locally required fields are present. Fields not supported ina country will be ignored. - Address documentation: https://backstage.sumup.net/docs/default/Component/merchants/merchant/#addresses + Address documentation: https://developer.sumup.com/tools/glossary/merchant#addresses """ birthdate: typing.Optional[datetime.date] = None @@ -336,12 +331,9 @@ class BasePerson(pydantic.BaseModel): citizenship: typing.Optional[CountryCode] = None """ - An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - country code. This definition users `oneOf` with a two-character string - type to allow for support of future countries in client code. + An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. This definition users`oneOf` with a two-character string type to allow for support of future countries in client code. Min length: 2 Max length: 2 - Pattern: ^[A-Z]{2}$ """ country_of_residence: typing.Optional[str] = None @@ -464,7 +456,7 @@ class BusinessProfile(pydantic.BaseModel): """ An address somewhere in the world. The address fields used depend on the country conventions. For example, inGreat Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addressesis `state`, whereas in Chile it's `region`. Whether an address is valid or not depends on whether the locally required fields are present. Fields not supported ina country will be ignored. - Address documentation: https://backstage.sumup.net/docs/default/Component/merchants/merchant/#addresses + Address documentation: https://developer.sumup.com/tools/glossary/merchant#addresses """ branding: typing.Optional[Branding] = None @@ -1509,7 +1501,7 @@ class Company(pydantic.BaseModel): """ An address somewhere in the world. The address fields used depend on the country conventions. For example, inGreat Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addressesis `state`, whereas in Chile it's `region`. Whether an address is valid or not depends on whether the locally required fields are present. Fields not supported ina country will be ignored. - Address documentation: https://backstage.sumup.net/docs/default/Component/merchants/merchant/#addresses + Address documentation: https://developer.sumup.com/tools/glossary/merchant#addresses """ attributes: typing.Optional[Attributes] = None @@ -1553,7 +1545,7 @@ class Company(pydantic.BaseModel): """ An address somewhere in the world. The address fields used depend on the country conventions. For example, inGreat Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addressesis `state`, whereas in Chile it's `region`. Whether an address is valid or not depends on whether the locally required fields are present. Fields not supported ina country will be ignored. - Address documentation: https://backstage.sumup.net/docs/default/Component/merchants/merchant/#addresses + Address documentation: https://developer.sumup.com/tools/glossary/merchant#addresses """ website: typing.Optional[str] = None @@ -2337,8 +2329,6 @@ class Event(pydantic.BaseModel): """ -FinancialPayoutStatus = typing.Union[typing.Literal["FAILED", "SUCCESSFUL"], str] - FinancialPayoutType = typing.Union[ typing.Literal[ "BALANCE_DEDUCTION", @@ -2350,37 +2340,68 @@ class Event(pydantic.BaseModel): str, ] +FinancialPayoutStatus = typing.Union[typing.Literal["FAILED", "SUCCESSFUL"], str] + class FinancialPayout(pydantic.BaseModel): """ - FinancialPayout is a schema definition. + A single payout-related record. + + A record can represent either: + - an actual payout sent to the merchant (`type = PAYOUT`) + - a deduction applied against merchant funds for a refund, chargeback, direct debit return, or balance adjustment """ - amount: typing.Optional[float] = None + amount: float + """ + Amount of the payout or deduction in major units. + """ - currency: typing.Optional[str] = None + currency: str + """ + Three-letter ISO 4217 currency code of the payout. + """ - date: typing.Optional[datetime.date] = None + date: datetime.date """ + Payout date associated with the record, in `YYYY-MM-DD` format. Format: date """ - fee: typing.Optional[float] = None + fee: float + """ + Fee amount associated with the payout record, in major units. + """ - id: typing.Optional[int] = None + id: int + """ + Unique identifier of the payout-related record. + """ - reference: typing.Optional[str] = None + reference: str + """ + Processor or payout reference associated with the record. + """ - status: typing.Optional[FinancialPayoutStatus] = None + status: FinancialPayoutStatus + """ + Merchant-facing outcome of the payout record. + """ - transaction_code: typing.Optional[str] = None + transaction_code: str + """ + Transaction code of the original sale associated with the payout or deduction. + """ - type: typing.Optional[FinancialPayoutType] = None + type: FinancialPayoutType + """ + High-level payout record category. + """ FinancialPayouts = list[FinancialPayout] """ -List of payout summaries. +Ordered list of payout and payout-deduction records. """ HorizontalAccuracy = float @@ -2458,7 +2479,7 @@ class Person(pydantic.BaseModel): """ An address somewhere in the world. The address fields used depend on the country conventions. For example, inGreat Britain, `city` is `post_town`. In the United States, the top-level administrative unit used in addressesis `state`, whereas in Chile it's `region`. Whether an address is valid or not depends on whether the locally required fields are present. Fields not supported ina country will be ignored. - Address documentation: https://backstage.sumup.net/docs/default/Component/merchants/merchant/#addresses + Address documentation: https://developer.sumup.com/tools/glossary/merchant#addresses """ birthdate: typing.Optional[datetime.date] = None @@ -2476,12 +2497,9 @@ class Person(pydantic.BaseModel): citizenship: typing.Optional[CountryCode] = None """ - An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - country code. This definition users `oneOf` with a two-character string - type to allow for support of future countries in client code. + An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. This definition users`oneOf` with a two-character string type to allow for support of future countries in client code. Min length: 2 Max length: 2 - Pattern: ^[A-Z]{2}$ """ country_of_residence: typing.Optional[str] = None @@ -2909,12 +2927,9 @@ class Merchant(pydantic.BaseModel): country: CountryCode """ - An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - country code. This definition users `oneOf` with a two-character string - type to allow for support of future countries in client code. + An [ISO3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. This definition users`oneOf` with a two-character string type to allow for support of future countries in client code. Min length: 2 Max length: 2 - Pattern: ^[A-Z]{2}$ """ created_at: datetime.datetime @@ -3034,59 +3049,6 @@ class NotFound(pydantic.BaseModel): errors: NotFoundErrors -class Permissions(pydantic.BaseModel): - """ - Permissions assigned to an operator or user. - """ - - admin: bool - - create_moto_payments: bool - - create_referral: bool - - full_transaction_history_view: bool - - refund_transactions: bool - - -OperatorAccountType = typing.Union[typing.Literal["normal", "operator"], str] - - -class Operator(pydantic.BaseModel): - """ - Operator account for a merchant. - """ - - account_type: OperatorAccountType - - created_at: datetime.datetime - """ - The timestamp of when the operator was created. - """ - - disabled: bool - - id: int - """ - Format: int32 - """ - - permissions: Permissions - """ - Permissions assigned to an operator or user. - """ - - updated_at: datetime.datetime - """ - The timestamp of when the operator was last updated. - """ - - username: str - - nickname: typing.Optional[str] = None - - PaymentInstrumentResponseType = typing.Union[typing.Literal["card"], str] diff --git a/tests/test_request_bodies.py b/tests/test_request_bodies.py index abd6987..f05a446 100644 --- a/tests/test_request_bodies.py +++ b/tests/test_request_bodies.py @@ -1,7 +1,5 @@ import datetime import json -import warnings - import httpx @@ -54,40 +52,3 @@ def handler(request: httpx.Request) -> httpx.Response: "merchant_code": "merchant-123", "valid_until": "2024-01-02T03:04:05", } - - -def test_update_subaccount_accepts_explicit_null_fields(sdk_factory): - captured_request: dict[str, httpx.Request] = {} - - def handler(request: httpx.Request) -> httpx.Response: - captured_request["request"] = request - return httpx.Response( - 200, - json={ - "account_type": "operator", - "created_at": "2024-01-01T00:00:00Z", - "disabled": False, - "id": 1, - "permissions": { - "admin": False, - "create_moto_payments": False, - "create_referral": False, - "full_transaction_history_view": False, - "refund_transactions": False, - }, - "updated_at": "2024-01-02T00:00:00Z", - "username": "operator@example.com", - "nickname": None, - }, - ) - - sdk = sdk_factory(handler) - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - response = sdk.subaccounts.update_sub_account(1, nickname=None) - - assert response.nickname is None - assert "request" in captured_request - request = captured_request["request"] - assert request.url.path == "/v0.1/me/accounts/1" - assert json.loads(request.content) == {"nickname": None}