bepaid 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bepaid-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.4
2
+ Name: bepaid
3
+ Version: 0.1.0
4
+ Summary: Client for the bePaid payment API (bepaid.by)
5
+ Author: amnesiaof
6
+ Author-email: amnesiaof <dolombovskyyalexs@gmail.com>
7
+ License-Expression: MIT
8
+ Requires-Dist: httpx>=0.27
9
+ Requires-Dist: pydantic>=2.7
10
+ Requires-Python: >=3.10
11
+ Project-URL: repository, https://github.com/amnesiaof/bepaid-py
12
+ Project-URL: homepage, https://github.com/amnesiaof/bepaid-py
13
+ Description-Content-Type: text/markdown
14
+
15
+ # bepaid
16
+
17
+ Python client for the [bePaid payment API](https://docs.bepaid.by) (bepaid.by).
18
+
19
+ Covers the Gateway API (card payments, tokenization, capture, void, refunds),
20
+ the hosted Checkout API, and the Direct/APM API (alternative payment methods).
21
+ Built on `httpx` and `pydantic`.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ uv add bepaid
27
+ # or
28
+ pip install bepaid
29
+ ```
30
+
31
+ Requires Python 3.10+.
32
+
33
+ ## Usage
34
+
35
+ ```python
36
+ from bepaid import BepaidClient
37
+ from bepaid.models import PaymentRequest, CreditCardRaw
38
+
39
+ client = BepaidClient("shop_id", "secret_key")
40
+
41
+ # amounts are strings in minor units, e.g. "700" = 7.00 BYN
42
+ payment = client.create_payment(
43
+ PaymentRequest(
44
+ amount="700",
45
+ currency="BYN",
46
+ test=True,
47
+ description="Order #123",
48
+ tracking_id="order-123",
49
+ credit_card=CreditCardRaw(
50
+ number="4242424242424242",
51
+ verification_value="123",
52
+ holder="John Smith",
53
+ exp_month=10,
54
+ exp_year=2030,
55
+ save_card=True,
56
+ ),
57
+ )
58
+ )
59
+ ```
60
+
61
+ Use the client as a context manager to close the underlying HTTP connection:
62
+
63
+ ```python
64
+ with BepaidClient("shop_id", "secret_key") as client:
65
+ payment = client.create_payment(...)
66
+ ```
67
+
68
+ ### Authorization with 3-D Secure
69
+
70
+ ```python
71
+ auth = client.create_authorization(AuthorizationRequest(amount=700, currency="BYN", ...))
72
+ # redirect the customer to auth.redirect_url, then poll for the result:
73
+ tx = client.get_transaction(auth.uid)
74
+ ```
75
+
76
+ ### Hosted checkout
77
+
78
+ ```python
79
+ checkout = client.create_checkout(
80
+ CheckoutRequest(
81
+ transaction_type="payment",
82
+ order=CheckoutOrder(currency="BYN", amount=700, description="Order #123"),
83
+ settings=CheckoutSettings(
84
+ return_url="https://example.com/return",
85
+ notification_url="https://example.com/webhook",
86
+ ),
87
+ )
88
+ )
89
+ # redirect the customer to checkout.redirect_url
90
+ ```
91
+
92
+ ### Tokenization
93
+
94
+ ```python
95
+ token = client.create_token(
96
+ CreateTokenRequest(
97
+ number="4200000000000000",
98
+ holder="John Smith",
99
+ exp_month="05",
100
+ exp_year="2028",
101
+ contract=["recurring"],
102
+ )
103
+ )
104
+ # store token.token, use it later without re-entering card details
105
+ ```
106
+
107
+ ### APM payments (Direct API)
108
+
109
+ ```python
110
+ apm = client.create_apm_payment(
111
+ ApmPaymentRequest(
112
+ amount=700,
113
+ currency="BYN",
114
+ payment_method={"type": "erip", "service_no": "0000000001"},
115
+ )
116
+ )
117
+ ```
118
+
119
+ ### Webhooks
120
+
121
+ ```python
122
+ from bepaid.client import verify_webhook_auth
123
+ from bepaid.models import WebhookNotification
124
+
125
+ assert verify_webhook_auth(authorization_header, shop_id, secret_key)
126
+ notification = WebhookNotification.model_validate_json(raw_body)
127
+ ```
128
+
129
+ ## API coverage
130
+
131
+ | Group | Operations |
132
+ |-----------|------------|
133
+ | Gateway | `create_payment`, `create_authorization`, `capture`, `void`, `refund`, `get_transaction` |
134
+ | Tokens | `create_token` |
135
+ | Checkout | `create_checkout`, `get_checkout_status`, `validate_apple_pay` |
136
+ | Direct | `create_apm_payment`, `apm_refund`, `apm_full_refund` |
137
+ | Webhooks | verification + payload parsing |
138
+
139
+ ## License
140
+
141
+ MIT
bepaid-0.1.0/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # bepaid
2
+
3
+ Python client for the [bePaid payment API](https://docs.bepaid.by) (bepaid.by).
4
+
5
+ Covers the Gateway API (card payments, tokenization, capture, void, refunds),
6
+ the hosted Checkout API, and the Direct/APM API (alternative payment methods).
7
+ Built on `httpx` and `pydantic`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ uv add bepaid
13
+ # or
14
+ pip install bepaid
15
+ ```
16
+
17
+ Requires Python 3.10+.
18
+
19
+ ## Usage
20
+
21
+ ```python
22
+ from bepaid import BepaidClient
23
+ from bepaid.models import PaymentRequest, CreditCardRaw
24
+
25
+ client = BepaidClient("shop_id", "secret_key")
26
+
27
+ # amounts are strings in minor units, e.g. "700" = 7.00 BYN
28
+ payment = client.create_payment(
29
+ PaymentRequest(
30
+ amount="700",
31
+ currency="BYN",
32
+ test=True,
33
+ description="Order #123",
34
+ tracking_id="order-123",
35
+ credit_card=CreditCardRaw(
36
+ number="4242424242424242",
37
+ verification_value="123",
38
+ holder="John Smith",
39
+ exp_month=10,
40
+ exp_year=2030,
41
+ save_card=True,
42
+ ),
43
+ )
44
+ )
45
+ ```
46
+
47
+ Use the client as a context manager to close the underlying HTTP connection:
48
+
49
+ ```python
50
+ with BepaidClient("shop_id", "secret_key") as client:
51
+ payment = client.create_payment(...)
52
+ ```
53
+
54
+ ### Authorization with 3-D Secure
55
+
56
+ ```python
57
+ auth = client.create_authorization(AuthorizationRequest(amount=700, currency="BYN", ...))
58
+ # redirect the customer to auth.redirect_url, then poll for the result:
59
+ tx = client.get_transaction(auth.uid)
60
+ ```
61
+
62
+ ### Hosted checkout
63
+
64
+ ```python
65
+ checkout = client.create_checkout(
66
+ CheckoutRequest(
67
+ transaction_type="payment",
68
+ order=CheckoutOrder(currency="BYN", amount=700, description="Order #123"),
69
+ settings=CheckoutSettings(
70
+ return_url="https://example.com/return",
71
+ notification_url="https://example.com/webhook",
72
+ ),
73
+ )
74
+ )
75
+ # redirect the customer to checkout.redirect_url
76
+ ```
77
+
78
+ ### Tokenization
79
+
80
+ ```python
81
+ token = client.create_token(
82
+ CreateTokenRequest(
83
+ number="4200000000000000",
84
+ holder="John Smith",
85
+ exp_month="05",
86
+ exp_year="2028",
87
+ contract=["recurring"],
88
+ )
89
+ )
90
+ # store token.token, use it later without re-entering card details
91
+ ```
92
+
93
+ ### APM payments (Direct API)
94
+
95
+ ```python
96
+ apm = client.create_apm_payment(
97
+ ApmPaymentRequest(
98
+ amount=700,
99
+ currency="BYN",
100
+ payment_method={"type": "erip", "service_no": "0000000001"},
101
+ )
102
+ )
103
+ ```
104
+
105
+ ### Webhooks
106
+
107
+ ```python
108
+ from bepaid.client import verify_webhook_auth
109
+ from bepaid.models import WebhookNotification
110
+
111
+ assert verify_webhook_auth(authorization_header, shop_id, secret_key)
112
+ notification = WebhookNotification.model_validate_json(raw_body)
113
+ ```
114
+
115
+ ## API coverage
116
+
117
+ | Group | Operations |
118
+ |-----------|------------|
119
+ | Gateway | `create_payment`, `create_authorization`, `capture`, `void`, `refund`, `get_transaction` |
120
+ | Tokens | `create_token` |
121
+ | Checkout | `create_checkout`, `get_checkout_status`, `validate_apple_pay` |
122
+ | Direct | `create_apm_payment`, `apm_refund`, `apm_full_refund` |
123
+ | Webhooks | verification + payload parsing |
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "bepaid"
3
+ version = "0.1.0"
4
+ description = "Client for the bePaid payment API (bepaid.by)"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ requires-python = ">=3.10"
8
+ dependencies = [
9
+ "httpx>=0.27",
10
+ "pydantic>=2.7",
11
+ ]
12
+
13
+ [[project.authors]]
14
+ name = "amnesiaof"
15
+ email = "dolombovskyyalexs@gmail.com"
16
+
17
+ [project.urls]
18
+ repository = "https://github.com/amnesiaof/bepaid-py"
19
+ homepage = "https://github.com/amnesiaof/bepaid-py"
20
+
21
+ [build-system]
22
+ requires = ["uv_build>=0.12.13,<0.13.0"]
23
+ build-backend = "uv_build"
24
+
25
+ [dependency-groups]
26
+ dev = ["pytest>=9.1.1"]
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "bepaid"
3
+ version = "0.1.0"
4
+ description = "Client for the bePaid payment API (bepaid.by)"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "amnesiaof", email = "dolombovskyyalexs@gmail.com" }
9
+ ]
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "httpx>=0.27",
13
+ "pydantic>=2.7",
14
+ ]
15
+
16
+ [project.urls]
17
+ repository = "https://github.com/amnesiaof/bepaid-py"
18
+ homepage = "https://github.com/amnesiaof/bepaid-py"
19
+
20
+ [build-system]
21
+ requires = ["uv_build>=0.12.13,<0.13.0"]
22
+ build-backend = "uv_build"
23
+
24
+ [dependency-groups]
25
+ dev = [
26
+ "pytest>=9.1.1",
27
+ ]
@@ -0,0 +1,7 @@
1
+ """bePaid payment API client (bepaid.by)."""
2
+
3
+ from .client import BepaidClient
4
+ from .errors import ApiError, BepaidError
5
+
6
+ __all__ = ["ApiError", "BepaidClient", "BepaidError"]
7
+ __version__ = "0.1.0"
@@ -0,0 +1,210 @@
1
+ """httpx-based client for the bePaid API (bepaid.by)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import base64
6
+ from typing import Any, Self
7
+
8
+ import httpx
9
+ from pydantic import BaseModel
10
+
11
+ from .errors import ApiError
12
+ from .models import (
13
+ ApmPaymentRequest,
14
+ ApmPaymentResponse,
15
+ ApmRefundRequest,
16
+ ApmRefundResponse,
17
+ AuthorizationRequest,
18
+ AuthorizationResponse,
19
+ CaptureRequest,
20
+ CaptureResponse,
21
+ CheckoutRequest,
22
+ CheckoutResponse,
23
+ CheckoutStatus,
24
+ CreateTokenRequest,
25
+ PaymentRequest,
26
+ PaymentResponse,
27
+ RefundRequest,
28
+ RefundResponse,
29
+ TokenResponse,
30
+ Transaction,
31
+ VoidRequest,
32
+ VoidResponse,
33
+ )
34
+
35
+ DEFAULT_GATEWAY_URL = "https://gateway.bepaid.by"
36
+ DEFAULT_CHECKOUT_URL = "https://checkout.bepaid.by"
37
+ DEFAULT_API_URL = "https://api.bepaid.by"
38
+
39
+ _HEADERS = {"Content-Type": "application/json", "Accept": "application/json"}
40
+
41
+
42
+ class BepaidClient:
43
+ def __init__(
44
+ self,
45
+ shop_id: str | int,
46
+ secret_key: str,
47
+ *,
48
+ timeout: float = 30.0,
49
+ base_gateway_url: str = DEFAULT_GATEWAY_URL,
50
+ base_checkout_url: str = DEFAULT_CHECKOUT_URL,
51
+ base_api_url: str = DEFAULT_API_URL,
52
+ ) -> None:
53
+ credentials = f"{shop_id}:{secret_key}"
54
+ self._auth = "Basic " + base64.b64encode(credentials.encode()).decode()
55
+ self._base_gateway = base_gateway_url
56
+ self._base_checkout = base_checkout_url
57
+ self._base_api = base_api_url
58
+ self._http = httpx.Client(timeout=timeout, headers=_HEADERS)
59
+
60
+ @property
61
+ def http(self) -> httpx.Client:
62
+ """The underlying synchronous httpx client (for advanced use)."""
63
+ return self._http
64
+
65
+ def close(self) -> None:
66
+ self._http.close()
67
+
68
+ def __enter__(self) -> Self:
69
+ return self
70
+
71
+ def __exit__(self, *exc: object) -> None:
72
+ self.close()
73
+
74
+ # ── transport ──────────────────────────────────────────────────────────
75
+
76
+ def _request(
77
+ self, method: str, url: str, body: BaseModel | dict | None = None
78
+ ) -> dict[str, Any]:
79
+ resp = self._http.request(
80
+ method,
81
+ url,
82
+ headers={"Authorization": self._auth},
83
+ json=body.model_dump(by_alias=True, exclude_none=True)
84
+ if isinstance(body, BaseModel)
85
+ else body,
86
+ )
87
+ if resp.status_code >= 400:
88
+ data = resp.json()
89
+ raise ApiError(
90
+ status=resp.status_code,
91
+ message=data.get("message", resp.text),
92
+ errors=data.get("errors"),
93
+ )
94
+ return resp.json()
95
+
96
+ # ── gateway API ────────────────────────────────────────────────────────
97
+
98
+ def create_payment(self, req: PaymentRequest) -> PaymentResponse:
99
+ data = self._request(
100
+ "POST",
101
+ f"{self._base_gateway}/transactions/payments",
102
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
103
+ )
104
+ return PaymentResponse.model_validate(data["transaction"])
105
+
106
+ def create_authorization(self, req: AuthorizationRequest) -> AuthorizationResponse:
107
+ data = self._request(
108
+ "POST",
109
+ f"{self._base_gateway}/transactions/authorizations",
110
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
111
+ )
112
+ return AuthorizationResponse.model_validate(data["transaction"])
113
+
114
+ def capture(self, req: CaptureRequest) -> CaptureResponse:
115
+ data = self._request(
116
+ "POST",
117
+ f"{self._base_gateway}/transactions/captures",
118
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
119
+ )
120
+ return CaptureResponse.model_validate(data["transaction"])
121
+
122
+ def void(self, req: VoidRequest) -> VoidResponse:
123
+ data = self._request(
124
+ "POST",
125
+ f"{self._base_gateway}/transactions/voids",
126
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
127
+ )
128
+ return VoidResponse.model_validate(data["transaction"])
129
+
130
+ def refund(self, req: RefundRequest) -> RefundResponse:
131
+ data = self._request(
132
+ "POST",
133
+ f"{self._base_gateway}/transactions/refunds",
134
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
135
+ )
136
+ return RefundResponse.model_validate(data["transaction"])
137
+
138
+ def get_transaction(self, uid: str) -> Transaction:
139
+ data = self._request("GET", f"{self._base_gateway}/transactions/{uid}")
140
+ return Transaction.model_validate(data["transaction"])
141
+
142
+ # ── token API ──────────────────────────────────────────────────────────
143
+
144
+ def create_token(self, req: CreateTokenRequest) -> TokenResponse:
145
+ data = self._request(
146
+ "POST",
147
+ f"{self._base_gateway}/credit_cards",
148
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
149
+ )
150
+ return TokenResponse.model_validate(data)
151
+
152
+ # ── checkout API ───────────────────────────────────────────────────────
153
+
154
+ def create_checkout(self, req: CheckoutRequest) -> CheckoutResponse:
155
+ data = self._request(
156
+ "POST",
157
+ f"{self._base_checkout}/ctp/api/checkouts",
158
+ {"checkout": req.model_dump(by_alias=True, exclude_none=True)},
159
+ )
160
+ return CheckoutResponse.model_validate(data["checkout"])
161
+
162
+ def get_checkout_status(self, token: str) -> CheckoutStatus:
163
+ data = self._request("GET", f"{self._base_checkout}/ctp/api/checkouts/{token}")
164
+ return CheckoutStatus.model_validate(data["checkout"])
165
+
166
+ def validate_apple_pay(self, url: str, token: str | None = None) -> dict[str, Any]:
167
+ return self._request(
168
+ "POST",
169
+ f"{self._base_checkout}/ctp/api/apple_pay/validate",
170
+ {"url": url, "token": token, "context": "merchant"},
171
+ )
172
+
173
+ # ── direct / APM API ───────────────────────────────────────────────────
174
+
175
+ def create_apm_payment(self, req: ApmPaymentRequest) -> ApmPaymentResponse:
176
+ data = self._request(
177
+ "POST",
178
+ f"{self._base_api}/beyag/transactions/payments",
179
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
180
+ )
181
+ return ApmPaymentResponse.model_validate(data["transaction"])
182
+
183
+ def apm_refund(self, req: ApmRefundRequest) -> ApmRefundResponse:
184
+ data = self._request(
185
+ "POST",
186
+ f"{self._base_api}/beyag/transactions/refunds",
187
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
188
+ )
189
+ return ApmRefundResponse.model_validate(data["transaction"])
190
+
191
+ def apm_full_refund(
192
+ self, parent_uid: str, reason: str, amount: int | None = None
193
+ ) -> ApmRefundResponse:
194
+ req = ApmRefundRequest(parent_uid=parent_uid, reason=reason, amount=amount)
195
+ data = self._request(
196
+ "POST",
197
+ f"{self._base_api}/beyag/refunds",
198
+ {"request": req.model_dump(by_alias=True, exclude_none=True)},
199
+ )
200
+ return ApmRefundResponse.model_validate(data["transaction"])
201
+
202
+
203
+ # ── webhook helpers ──────────────────────────────────────────────────────────
204
+
205
+
206
+ def verify_webhook_auth(
207
+ authorization_header: str, shop_id: str, secret_key: str
208
+ ) -> bool:
209
+ expected = "Basic " + base64.b64encode(f"{shop_id}:{secret_key}".encode()).decode()
210
+ return authorization_header == expected
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ class BepaidError(Exception):
7
+ """Base exception for bepaid errors."""
8
+
9
+
10
+ @dataclass
11
+ class ApiError(BepaidError):
12
+ """An error response returned by the bePaid API."""
13
+
14
+ status: int
15
+ message: str
16
+ errors: dict | None = None
17
+
18
+ def __str__(self) -> str:
19
+ return f"API error {self.status}: {self.message}"
@@ -0,0 +1,371 @@
1
+ """Pydantic models for the bePaid API (aliases use camelCase as the API expects)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+ from pydantic.alias_generators import to_camel
9
+
10
+
11
+ class CamelModel(BaseModel):
12
+ model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
13
+
14
+
15
+ class BillingAddress(CamelModel):
16
+ first_name: str | None = None
17
+ last_name: str | None = None
18
+ country: str | None = None
19
+ city: str | None = None
20
+ state: str | None = None
21
+ zip: str | None = None
22
+ address: str | None = None
23
+ phone: str | None = None
24
+
25
+
26
+ class Customer(CamelModel):
27
+ first_name: str | None = None
28
+ last_name: str | None = None
29
+ middle_name: str | None = None
30
+ ip: str | None = None
31
+ email: str | None = None
32
+ device_id: str | None = None
33
+ birth_date: str | None = None
34
+
35
+
36
+ class BrowserInfo(CamelModel):
37
+ screen_width: int | None = None
38
+ screen_height: int | None = None
39
+ screen_color_depth: int | None = None
40
+ language: str | None = None
41
+ java_enabled: bool | None = None
42
+ user_agent: str | None = None
43
+ time_zone: int | None = None
44
+ time_zone_name: str | None = None
45
+ accept_header: str | None = None
46
+ window_height: int | None = None
47
+ window_width: int | None = None
48
+
49
+
50
+ class AdditionalData(CamelModel):
51
+ browser: BrowserInfo | None = None
52
+ contract: list[str] | None = None
53
+ referer: str | None = None
54
+
55
+
56
+ class CreditCardRaw(CamelModel):
57
+ number: str
58
+ verification_value: str | None = None
59
+ holder: str | None = None
60
+ exp_month: int | None = None
61
+ exp_year: int | None = None
62
+ save_card: bool | None = None
63
+ token: str | None = None
64
+
65
+
66
+ class CreditCardInfo(CamelModel):
67
+ holder: str | None = None
68
+ stamp: str | None = None
69
+ brand: str | None = None
70
+ last_4: str | None = None
71
+ first_1: str | None = None
72
+ bin: str | None = None
73
+ exp_month: int | None = None
74
+ exp_year: int | None = None
75
+ token: str | None = None
76
+
77
+
78
+ class PaymentInfo(CamelModel):
79
+ auth_code: str | None = None
80
+ bank_code: str | None = None
81
+ rrn: str | None = None
82
+ ref_id: str | None = None
83
+ message: str | None = None
84
+ amount: int | None = None
85
+ currency: str | None = None
86
+ billing_descriptor: str | None = None
87
+ gateway_id: int | None = None
88
+ status: str | None = None
89
+
90
+
91
+ class ThreeDSecureVerification(CamelModel):
92
+ status: str | None = None
93
+ message: str | None = None
94
+ pa_res_url: str | None = None
95
+ eci: str | None = None
96
+
97
+
98
+ # ── gateway ───────────────────────────────────────────────────────────────────
99
+
100
+
101
+ class PaymentRequest(CamelModel):
102
+ amount: str
103
+ currency: str
104
+ test: bool
105
+ description: str
106
+ tracking_id: str
107
+ language: str | None = None
108
+ notification_url: str | None = None
109
+ billing_address: BillingAddress | None = None
110
+ credit_card: CreditCardRaw | None = None
111
+ customer: Customer | None = None
112
+ additional_data: AdditionalData | None = None
113
+
114
+
115
+ class PaymentResponse(CamelModel):
116
+ tracking_id: str | None = None
117
+ uid: str
118
+
119
+
120
+ class AuthorizationRequest(CamelModel):
121
+ amount: int
122
+ currency: str
123
+ description: str
124
+ tracking_id: str
125
+ payment_method_type: str | None = None
126
+ test: bool | None = None
127
+ credit_card: CreditCardRaw | None = None
128
+ customer: Customer | None = None
129
+ billing_address: BillingAddress | None = None
130
+
131
+
132
+ class AuthorizationResponse(CamelModel):
133
+ uid: str
134
+ status: str | None = None
135
+ redirect_url: str | None = None
136
+ three_d_secure_verification: ThreeDSecureVerification | None = None
137
+
138
+
139
+ class Transaction(CamelModel):
140
+ uid: str
141
+ status: str | None = None
142
+ amount: int | None = None
143
+ currency: str | None = None
144
+ description: str | None = None
145
+ tracking_id: str | None = None
146
+ message: str | None = None
147
+ type: str | None = None
148
+ test: bool | None = None
149
+ payment: PaymentInfo | None = None
150
+ credit_card: CreditCardInfo | None = None
151
+ code: str | None = None
152
+ friendly_message: str | None = None
153
+ created_at: str | None = None
154
+ updated_at: str | None = None
155
+ paid_at: str | None = None
156
+ receipt_url: str | None = None
157
+ redirect_url: str | None = None
158
+
159
+
160
+ class CaptureRequest(CamelModel):
161
+ parent_uid: str
162
+ amount: int
163
+ tracking_id: str | None = None
164
+ additional_data: AdditionalData | None = None
165
+
166
+
167
+ class CaptureResponse(CamelModel):
168
+ uid: str
169
+ status: str | None = None
170
+ type: str | None = None
171
+ parent_uid: str | None = None
172
+ amount: int | None = None
173
+ currency: str | None = None
174
+ code: str | None = None
175
+
176
+
177
+ class VoidRequest(CamelModel):
178
+ parent_uid: str
179
+ amount: int
180
+ tracking_id: str | None = None
181
+ additional_data: AdditionalData | None = None
182
+
183
+
184
+ class VoidResponse(CamelModel):
185
+ uid: str
186
+ status: str | None = None
187
+ type: str | None = None
188
+ message: str | None = None
189
+ code: str | None = None
190
+ tracking_id: str | None = None
191
+ receipt_url: str | None = None
192
+
193
+
194
+ class RefundRequest(CamelModel):
195
+ parent_uid: str
196
+ amount: int
197
+ reason: str
198
+ tracking_id: str | None = None
199
+ additional_data: AdditionalData | None = None
200
+
201
+
202
+ class RefundResponse(CamelModel):
203
+ uid: str | None = None
204
+ parent_uid: str | None = None
205
+ type: str | None = None
206
+ status: str | None = None
207
+ message: str | None = None
208
+ amount: int | None = None
209
+ currency: str | None = None
210
+ created_at: str | None = None
211
+ reason: str | None = None
212
+ refund: dict[str, Any] | None = None
213
+
214
+
215
+ # ── token API ─────────────────────────────────────────────────────────────────
216
+
217
+
218
+ class CreateTokenRequest(CamelModel):
219
+ number: str
220
+ holder: str
221
+ exp_month: str
222
+ exp_year: str
223
+ contract: list[str] | None = None
224
+
225
+
226
+ class TokenResponse(CamelModel):
227
+ holder: str | None = None
228
+ stamp: str | None = None
229
+ brand: str | None = None
230
+ last_4: str | None = None
231
+ first_1: str | None = None
232
+ token: str | None = None
233
+ exp_month: int | None = None
234
+ exp_year: int | None = None
235
+
236
+
237
+ # ── checkout API ──────────────────────────────────────────────────────────────
238
+
239
+
240
+ class CheckoutSettings(CamelModel):
241
+ return_url: str | None = None
242
+ success_url: str | None = None
243
+ decline_url: str | None = None
244
+ fail_url: str | None = None
245
+ cancel_url: str | None = None
246
+ notification_url: str | None = None
247
+ button_next_text: str | None = None
248
+ auto_pay: bool | None = None
249
+ language: str | None = None
250
+
251
+
252
+ class PaymentMethod(CamelModel):
253
+ types: list[str] | None = None
254
+
255
+
256
+ class CheckoutCreditCard(CamelModel):
257
+ token: str | None = None
258
+
259
+
260
+ class CheckoutOrder(CamelModel):
261
+ currency: str
262
+ amount: int
263
+ description: str | None = None
264
+ tracking_id: str | None = None
265
+
266
+
267
+ class CheckoutRequest(CamelModel):
268
+ test: bool | None = None
269
+ transaction_type: str = "payment"
270
+ attempts: int | None = None
271
+ iframe: bool | None = None
272
+ settings: CheckoutSettings | None = None
273
+ payment_method: PaymentMethod | None = None
274
+ credit_card: CheckoutCreditCard | None = None
275
+ order: CheckoutOrder
276
+ customer: Customer | None = None
277
+
278
+
279
+ class CheckoutResponse(CamelModel):
280
+ token: str
281
+ redirect_url: str | None = None
282
+
283
+
284
+ class CheckoutStatus(CamelModel):
285
+ token: str | None = None
286
+ shop_id: int | None = None
287
+ transaction_type: str | None = None
288
+ gateway_response: dict[str, Any] | None = None
289
+ order: dict[str, Any] | None = None
290
+ settings: CheckoutSettings | None = None
291
+
292
+
293
+ # ── direct / APM API ──────────────────────────────────────────────────────────
294
+
295
+
296
+ class ApmPaymentRequest(CamelModel):
297
+ amount: int
298
+ currency: str
299
+ description: str | None = None
300
+ email: str | None = None
301
+ ip: str | None = None
302
+ success_url: str | None = None
303
+ order_id: str | int | None = None
304
+ tracking_id: str | None = None
305
+ notification_url: str | None = None
306
+ expired_at: str | None = None
307
+ test: bool | None = None
308
+ language: str | None = None
309
+ return_url: str | None = None
310
+ customer: Customer | None = None
311
+ payment_method: dict[str, Any] = Field(alias="paymentMethod")
312
+ additional_data: dict[str, Any] | None = None
313
+
314
+
315
+ class ApmPaymentResponse(CamelModel):
316
+ uid: str | None = None
317
+ status: str | None = None
318
+ type: str | None = None
319
+ amount: int | None = None
320
+ currency: str | None = None
321
+ message: str | None = None
322
+ tracking_id: str | None = None
323
+ test: bool | None = None
324
+ method_type: str | None = None
325
+ receipt_url: str | None = None
326
+ payment: PaymentInfo | None = None
327
+ created_at: str | None = None
328
+
329
+
330
+ class ApmRefundRequest(CamelModel):
331
+ parent_uid: str
332
+ reason: str
333
+ amount: int | None = None
334
+ tracking_id: str | None = None
335
+ additional_data: dict[str, Any] | None = None
336
+
337
+
338
+ class ApmRefundResponse(CamelModel):
339
+ uid: str | None = None
340
+ parent_uid: str | None = None
341
+ type: str | None = None
342
+ status: str | None = None
343
+ message: str | None = None
344
+ amount: int | None = None
345
+ currency: str | None = None
346
+ refund: dict[str, Any] | None = None
347
+
348
+
349
+ # ── webhook ───────────────────────────────────────────────────────────────────
350
+
351
+
352
+ class WebhookNotification(CamelModel):
353
+ transaction: WebhookTransaction
354
+
355
+
356
+ class WebhookTransaction(CamelModel):
357
+ uid: str
358
+ status: str
359
+ type: str | None = None
360
+ amount: int | None = None
361
+ currency: str | None = None
362
+ description: str | None = None
363
+ created_at: str | None = None
364
+ method_type: str | None = None
365
+ payment: PaymentInfo | None = None
366
+ message: str | None = None
367
+ tracking_id: str | None = None
368
+ test: bool | None = None
369
+
370
+
371
+ WebhookNotification.model_rebuild()