integrax 1.0.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.
integrax-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 IntegraX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: integrax
3
+ Version: 1.0.0
4
+ Summary: Send SMS, RCS & OTP messages via API. Bulk SMS, OTP verification, phone number lookup.
5
+ Author-email: Integrax <contato@integrax.lat>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://integrax.lat
8
+ Project-URL: Documentation, https://integrax.lat/desenvolvedores
9
+ Project-URL: Repository, https://github.com/integrax-lat/integrax-python
10
+ Project-URL: Create Account, https://integrax.app
11
+ Keywords: sms,send-sms,bulk-sms,sms-api,rcs,otp,otp-verification,verify-phone,phone-verification,messaging,cpaas,text-message,integrax,api
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Typing :: Typed
21
+ Classifier: Topic :: Communications
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: httpx>=0.25.0
27
+ Dynamic: license-file
28
+
29
+ # integrax
30
+
31
+ SDK oficial da Integrax para Python — SMS, RCS, OTP e consultas via API REST.
32
+
33
+ - Usa [httpx](https://www.python-httpx.org/) como HTTP client
34
+ - Type hints completos (PEP 561 — `py.typed`)
35
+ - Python 3.9+
36
+
37
+ ## Obtendo seu token
38
+
39
+ 1. Crie uma conta gratuita em [integrax.app](https://integrax.app)
40
+ 2. Após o cadastro, acesse o menu **API** e crie um token
41
+
42
+ Pronto, você já pode integrar!
43
+
44
+ > Se receber `MESSAGE_NOT_ALLOWED`, entre em contato com o suporte pelo [WhatsApp](https://wa.me/551132808396) e solicite a liberação.
45
+
46
+ ## Instalação
47
+
48
+ ```bash
49
+ pip install integrax
50
+ ```
51
+
52
+ ## Quick start
53
+
54
+ ```python
55
+ from integrax import Integrax
56
+
57
+ ix = Integrax("seu-token-aqui")
58
+
59
+ # Enviar SMS
60
+ res = ix.sms.send(["5511999999999"], "Pedido #4821 confirmado ✓")
61
+ print(res["data"][0]["messageId"]) # "82816396"
62
+ ```
63
+
64
+ Ou com context manager:
65
+
66
+ ```python
67
+ with Integrax("seu-token") as ix:
68
+ ix.sms.send(["5511999999999"], "Olá!")
69
+ ```
70
+
71
+ ## Configuração
72
+
73
+ ```python
74
+ ix = Integrax(
75
+ "seu-token",
76
+ base_url="https://sms.aresfun.com", # padrão
77
+ timeout=15.0, # padrão: 30s
78
+ )
79
+ ```
80
+
81
+ ## SMS
82
+
83
+ ```python
84
+ # Envio simples (usa shortcode padrão da conta)
85
+ res = ix.sms.send(["5511999999999", "5521888888888"], "Sua mensagem aqui")
86
+
87
+ # Com shortcode customizado
88
+ res = ix.sms.send(["5511999999999"], "Olá!", from_="29094")
89
+
90
+ # res["code"] == "SMS_SENT"
91
+ # res["data"][0]["status"] == "SENT_TO_OPERATOR"
92
+ # res["data"][0]["messageId"] == "82816396"
93
+ ```
94
+
95
+ ### DLR (webhook)
96
+
97
+ Configure seu webhook para receber o status de entrega:
98
+
99
+ ```python
100
+ # Payload recebido no seu endpoint
101
+ {
102
+ "message_id": "82816396",
103
+ "status": "DELIVRD", # DELIVRD | EXPIRED | REJECTD | UNDELIV
104
+ "number": "5511999999999"
105
+ }
106
+ ```
107
+
108
+ ## OTP
109
+
110
+ Duas chamadas: enviar código e verificar.
111
+
112
+ ```python
113
+ # 1. Envio mínimo (usa todos os defaults: 6 dígitos numéricos, expira em 10min)
114
+ ix.otp.send("5511999999999")
115
+
116
+ # 1b. Personalizado
117
+ ix.otp.send(
118
+ "5511999999999",
119
+ message_default="Use [code] pra confirmar sua conta", # padrão: "Seu código: [code]"
120
+ from_="29094", # se omitido, usa o padrão da conta
121
+ qtd_digits=5, # padrão: 6
122
+ with_text=True, # alfanumérico (padrão: False = só números)
123
+ expires_in=5, # minutos (padrão: 10)
124
+ )
125
+
126
+ # 2. Verificar código digitado pelo usuário
127
+ res = ix.otp.verify("1MP5L", "5511999999999")
128
+ if res["status"] == "verified":
129
+ print("Código válido!")
130
+ ```
131
+
132
+ ## RCS
133
+
134
+ ### BASIC (só texto)
135
+
136
+ ```python
137
+ ix.rcs.send(
138
+ ["5511999999999"],
139
+ "Olá! Mensagem RCS básica.",
140
+ "IntegraX",
141
+ rcs_type="BASIC",
142
+ )
143
+ ```
144
+
145
+ ### RICH (card com mídia e botões)
146
+
147
+ ```python
148
+ ix.rcs.send(
149
+ ["5511999999999"],
150
+ "Confira nossa oferta!",
151
+ "IntegraX",
152
+ rcs_message={
153
+ "card": {
154
+ "title": "Black Friday",
155
+ "description": "Até 60% OFF em todos os produtos.",
156
+ "media": {
157
+ "file": {"url": "https://exemplo.com/banner.png"},
158
+ "height": "MEDIUM",
159
+ },
160
+ "suggestions": [
161
+ {
162
+ "type": "OPEN_URL",
163
+ "text": "Ver ofertas",
164
+ "url": "https://exemplo.com/ofertas",
165
+ "postbackData": "click_ofertas",
166
+ }
167
+ ],
168
+ }
169
+ },
170
+ )
171
+ ```
172
+
173
+ ## Créditos
174
+
175
+ ```python
176
+ balance = ix.credits.balance()
177
+ print(balance)
178
+ ```
179
+
180
+ ## Consultas
181
+
182
+ ### Por CPF
183
+
184
+ ```python
185
+ res = ix.consult.cpf(["00000000001"], show_phone_valid=True, show_restrictions=True)
186
+ ```
187
+
188
+ ### Por telefone
189
+
190
+ ```python
191
+ res = ix.consult.phone(["551199999999"])
192
+ ```
193
+
194
+ ### Telefone premium (dados enriquecidos)
195
+
196
+ ```python
197
+ res = ix.consult.phone_premium(["551199999999"])
198
+ ```
199
+
200
+ ## Números internacionais
201
+
202
+ - Para números de outros países, insira `+` na frente do número (ex: `+34992000000`).
203
+ - Para envios internacionais, é necessário solicitar a ativação da rota através do suporte.
204
+ - Alguns países permitem `from` personalizado. Se permitido, basta informar o `from` no payload.
205
+
206
+ ## Tratamento de erros
207
+
208
+ ```python
209
+ from integrax import Integrax, IntegraxError
210
+
211
+ try:
212
+ ix.sms.send(["551100000000"], "teste")
213
+ except IntegraxError as e:
214
+ print(e.status) # HTTP status (ex: 401, 422)
215
+ print(e.code) # código da API
216
+ print(e.body) # corpo completo da resposta
217
+ ```
218
+
219
+ ## Licença
220
+
221
+ MIT
@@ -0,0 +1,193 @@
1
+ # integrax
2
+
3
+ SDK oficial da Integrax para Python — SMS, RCS, OTP e consultas via API REST.
4
+
5
+ - Usa [httpx](https://www.python-httpx.org/) como HTTP client
6
+ - Type hints completos (PEP 561 — `py.typed`)
7
+ - Python 3.9+
8
+
9
+ ## Obtendo seu token
10
+
11
+ 1. Crie uma conta gratuita em [integrax.app](https://integrax.app)
12
+ 2. Após o cadastro, acesse o menu **API** e crie um token
13
+
14
+ Pronto, você já pode integrar!
15
+
16
+ > Se receber `MESSAGE_NOT_ALLOWED`, entre em contato com o suporte pelo [WhatsApp](https://wa.me/551132808396) e solicite a liberação.
17
+
18
+ ## Instalação
19
+
20
+ ```bash
21
+ pip install integrax
22
+ ```
23
+
24
+ ## Quick start
25
+
26
+ ```python
27
+ from integrax import Integrax
28
+
29
+ ix = Integrax("seu-token-aqui")
30
+
31
+ # Enviar SMS
32
+ res = ix.sms.send(["5511999999999"], "Pedido #4821 confirmado ✓")
33
+ print(res["data"][0]["messageId"]) # "82816396"
34
+ ```
35
+
36
+ Ou com context manager:
37
+
38
+ ```python
39
+ with Integrax("seu-token") as ix:
40
+ ix.sms.send(["5511999999999"], "Olá!")
41
+ ```
42
+
43
+ ## Configuração
44
+
45
+ ```python
46
+ ix = Integrax(
47
+ "seu-token",
48
+ base_url="https://sms.aresfun.com", # padrão
49
+ timeout=15.0, # padrão: 30s
50
+ )
51
+ ```
52
+
53
+ ## SMS
54
+
55
+ ```python
56
+ # Envio simples (usa shortcode padrão da conta)
57
+ res = ix.sms.send(["5511999999999", "5521888888888"], "Sua mensagem aqui")
58
+
59
+ # Com shortcode customizado
60
+ res = ix.sms.send(["5511999999999"], "Olá!", from_="29094")
61
+
62
+ # res["code"] == "SMS_SENT"
63
+ # res["data"][0]["status"] == "SENT_TO_OPERATOR"
64
+ # res["data"][0]["messageId"] == "82816396"
65
+ ```
66
+
67
+ ### DLR (webhook)
68
+
69
+ Configure seu webhook para receber o status de entrega:
70
+
71
+ ```python
72
+ # Payload recebido no seu endpoint
73
+ {
74
+ "message_id": "82816396",
75
+ "status": "DELIVRD", # DELIVRD | EXPIRED | REJECTD | UNDELIV
76
+ "number": "5511999999999"
77
+ }
78
+ ```
79
+
80
+ ## OTP
81
+
82
+ Duas chamadas: enviar código e verificar.
83
+
84
+ ```python
85
+ # 1. Envio mínimo (usa todos os defaults: 6 dígitos numéricos, expira em 10min)
86
+ ix.otp.send("5511999999999")
87
+
88
+ # 1b. Personalizado
89
+ ix.otp.send(
90
+ "5511999999999",
91
+ message_default="Use [code] pra confirmar sua conta", # padrão: "Seu código: [code]"
92
+ from_="29094", # se omitido, usa o padrão da conta
93
+ qtd_digits=5, # padrão: 6
94
+ with_text=True, # alfanumérico (padrão: False = só números)
95
+ expires_in=5, # minutos (padrão: 10)
96
+ )
97
+
98
+ # 2. Verificar código digitado pelo usuário
99
+ res = ix.otp.verify("1MP5L", "5511999999999")
100
+ if res["status"] == "verified":
101
+ print("Código válido!")
102
+ ```
103
+
104
+ ## RCS
105
+
106
+ ### BASIC (só texto)
107
+
108
+ ```python
109
+ ix.rcs.send(
110
+ ["5511999999999"],
111
+ "Olá! Mensagem RCS básica.",
112
+ "IntegraX",
113
+ rcs_type="BASIC",
114
+ )
115
+ ```
116
+
117
+ ### RICH (card com mídia e botões)
118
+
119
+ ```python
120
+ ix.rcs.send(
121
+ ["5511999999999"],
122
+ "Confira nossa oferta!",
123
+ "IntegraX",
124
+ rcs_message={
125
+ "card": {
126
+ "title": "Black Friday",
127
+ "description": "Até 60% OFF em todos os produtos.",
128
+ "media": {
129
+ "file": {"url": "https://exemplo.com/banner.png"},
130
+ "height": "MEDIUM",
131
+ },
132
+ "suggestions": [
133
+ {
134
+ "type": "OPEN_URL",
135
+ "text": "Ver ofertas",
136
+ "url": "https://exemplo.com/ofertas",
137
+ "postbackData": "click_ofertas",
138
+ }
139
+ ],
140
+ }
141
+ },
142
+ )
143
+ ```
144
+
145
+ ## Créditos
146
+
147
+ ```python
148
+ balance = ix.credits.balance()
149
+ print(balance)
150
+ ```
151
+
152
+ ## Consultas
153
+
154
+ ### Por CPF
155
+
156
+ ```python
157
+ res = ix.consult.cpf(["00000000001"], show_phone_valid=True, show_restrictions=True)
158
+ ```
159
+
160
+ ### Por telefone
161
+
162
+ ```python
163
+ res = ix.consult.phone(["551199999999"])
164
+ ```
165
+
166
+ ### Telefone premium (dados enriquecidos)
167
+
168
+ ```python
169
+ res = ix.consult.phone_premium(["551199999999"])
170
+ ```
171
+
172
+ ## Números internacionais
173
+
174
+ - Para números de outros países, insira `+` na frente do número (ex: `+34992000000`).
175
+ - Para envios internacionais, é necessário solicitar a ativação da rota através do suporte.
176
+ - Alguns países permitem `from` personalizado. Se permitido, basta informar o `from` no payload.
177
+
178
+ ## Tratamento de erros
179
+
180
+ ```python
181
+ from integrax import Integrax, IntegraxError
182
+
183
+ try:
184
+ ix.sms.send(["551100000000"], "teste")
185
+ except IntegraxError as e:
186
+ print(e.status) # HTTP status (ex: 401, 422)
187
+ print(e.code) # código da API
188
+ print(e.body) # corpo completo da resposta
189
+ ```
190
+
191
+ ## Licença
192
+
193
+ MIT
@@ -0,0 +1,51 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "integrax"
7
+ version = "1.0.0"
8
+ description = "Send SMS, RCS & OTP messages via API. Bulk SMS, OTP verification, phone number lookup."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [{ name = "Integrax", email = "contato@integrax.lat" }]
13
+ keywords = [
14
+ "sms",
15
+ "send-sms",
16
+ "bulk-sms",
17
+ "sms-api",
18
+ "rcs",
19
+ "otp",
20
+ "otp-verification",
21
+ "verify-phone",
22
+ "phone-verification",
23
+ "messaging",
24
+ "cpaas",
25
+ "text-message",
26
+ "integrax",
27
+ "api",
28
+ ]
29
+ classifiers = [
30
+ "Development Status :: 5 - Production/Stable",
31
+ "Intended Audience :: Developers",
32
+ "Programming Language :: Python :: 3",
33
+ "Programming Language :: Python :: 3.9",
34
+ "Programming Language :: Python :: 3.10",
35
+ "Programming Language :: Python :: 3.11",
36
+ "Programming Language :: Python :: 3.12",
37
+ "Programming Language :: Python :: 3.13",
38
+ "Typing :: Typed",
39
+ "Topic :: Communications",
40
+ "Topic :: Software Development :: Libraries :: Python Modules",
41
+ ]
42
+ dependencies = ["httpx>=0.25.0"]
43
+
44
+ [project.urls]
45
+ Homepage = "https://integrax.lat"
46
+ Documentation = "https://integrax.lat/desenvolvedores"
47
+ Repository = "https://github.com/integrax-lat/integrax-python"
48
+ "Create Account" = "https://integrax.app"
49
+
50
+ [tool.setuptools.packages.find]
51
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ """SDK oficial da Integrax — SMS, RCS, OTP e consultas via API REST."""
2
+
3
+ from .client import Integrax, IntegraxError
4
+
5
+ __all__ = ["Integrax", "IntegraxError"]
6
+ __version__ = "1.0.0"
@@ -0,0 +1,106 @@
1
+ """Cliente HTTP e classe principal do SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from .sms import Sms
10
+ from .otp import Otp
11
+ from .rcs import Rcs
12
+ from .credits import Credits
13
+ from .consult import Consult
14
+
15
+
16
+ class IntegraxError(Exception):
17
+ """Erro retornado pela API da Integrax."""
18
+
19
+ def __init__(self, status: int, message: str, code: str | None = None, body: Any = None):
20
+ super().__init__(message)
21
+ self.status = status
22
+ self.code = code
23
+ self.body = body
24
+
25
+
26
+ class HttpClient:
27
+ """Cliente HTTP interno — não usar diretamente."""
28
+
29
+ def __init__(self, token: str, base_url: str, timeout: float):
30
+ self._token = token
31
+ self._base_url = base_url.rstrip("/")
32
+ self._client = httpx.Client(
33
+ timeout=timeout,
34
+ headers={"Content-Type": "application/json", "Accept": "application/json"},
35
+ )
36
+
37
+ def _url(self, path: str) -> str:
38
+ return f"{self._base_url}/v1/integration/{self._token}{path}"
39
+
40
+ def _handle(self, res: httpx.Response) -> Any:
41
+ try:
42
+ data = res.json()
43
+ except Exception:
44
+ data = None
45
+
46
+ if not res.is_success:
47
+ raise IntegraxError(
48
+ status=res.status_code,
49
+ message=data.get("message", f"HTTP {res.status_code}") if isinstance(data, dict) else f"HTTP {res.status_code}",
50
+ code=data.get("code") if isinstance(data, dict) else None,
51
+ body=data,
52
+ )
53
+ return data
54
+
55
+ def get(self, path: str) -> Any:
56
+ return self._handle(self._client.get(self._url(path)))
57
+
58
+ def post(self, path: str, body: dict[str, Any] | None = None) -> Any:
59
+ return self._handle(self._client.post(self._url(path), json=body))
60
+
61
+ def close(self) -> None:
62
+ self._client.close()
63
+
64
+
65
+ class Integrax:
66
+ """
67
+ SDK da Integrax.
68
+
69
+ Args:
70
+ token: Token de integração.
71
+ base_url: URL base da API (padrão: https://sms.aresfun.com).
72
+ timeout: Timeout em segundos (padrão: 30).
73
+
74
+ Exemplo::
75
+
76
+ ix = Integrax("seu-token-aqui")
77
+ res = ix.sms.send(["5511999999999"], "Pedido confirmado ✓")
78
+ """
79
+
80
+ def __init__(
81
+ self,
82
+ token: str,
83
+ *,
84
+ base_url: str = "https://sms.aresfun.com",
85
+ timeout: float = 30.0,
86
+ ):
87
+ if not token:
88
+ raise ValueError("Integrax: token é obrigatório")
89
+
90
+ self._http = HttpClient(token, base_url, timeout)
91
+
92
+ self.sms = Sms(self._http)
93
+ self.otp = Otp(self._http)
94
+ self.rcs = Rcs(self._http)
95
+ self.credits = Credits(self._http)
96
+ self.consult = Consult(self._http)
97
+
98
+ def close(self) -> None:
99
+ """Fecha o cliente HTTP."""
100
+ self._http.close()
101
+
102
+ def __enter__(self) -> Integrax:
103
+ return self
104
+
105
+ def __exit__(self, *_: Any) -> None:
106
+ self.close()
@@ -0,0 +1,65 @@
1
+ """Recurso Consult."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from .client import HttpClient
9
+
10
+
11
+ class Consult:
12
+ def __init__(self, http: HttpClient):
13
+ self._http = http
14
+
15
+ def cpf(
16
+ self,
17
+ documents: list[str],
18
+ *,
19
+ show_phone_valid: bool | None = None,
20
+ show_restrictions: bool | None = None,
21
+ ) -> dict[str, Any]:
22
+ """
23
+ Consulta dados por CPF.
24
+
25
+ Args:
26
+ documents: Lista de CPFs (apenas números).
27
+ show_phone_valid: Retornar telefones válidos.
28
+ show_restrictions: Retornar restrições.
29
+
30
+ Exemplo::
31
+
32
+ res = ix.consult.cpf(["00000000001"], show_phone_valid=True)
33
+ """
34
+ body: dict[str, Any] = {"documents": documents, "type": "cpf"}
35
+ if show_phone_valid is not None:
36
+ body["showPhoneValid"] = show_phone_valid
37
+ if show_restrictions is not None:
38
+ body["showRestrictions"] = show_restrictions
39
+ return self._http.post("/consult", body)
40
+
41
+ def phone(self, phones: list[str]) -> dict[str, Any]:
42
+ """
43
+ Consulta dados por número de telefone.
44
+
45
+ Args:
46
+ phones: Lista de telefones.
47
+
48
+ Exemplo::
49
+
50
+ res = ix.consult.phone(["551199999999"])
51
+ """
52
+ return self._http.post("/consult-phone", {"phones": phones})
53
+
54
+ def phone_premium(self, phones: list[str]) -> dict[str, Any]:
55
+ """
56
+ Consulta premium por número de telefone (dados enriquecidos).
57
+
58
+ Args:
59
+ phones: Lista de telefones.
60
+
61
+ Exemplo::
62
+
63
+ res = ix.consult.phone_premium(["551199999999"])
64
+ """
65
+ return self._http.post("/consult-phone-premium", {"phones": phones})
@@ -0,0 +1,24 @@
1
+ """Recurso Credits."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from .client import HttpClient
9
+
10
+
11
+ class Credits:
12
+ def __init__(self, http: HttpClient):
13
+ self._http = http
14
+
15
+ def balance(self) -> dict[str, Any]:
16
+ """
17
+ Consulta o saldo de créditos da conta.
18
+
19
+ Exemplo::
20
+
21
+ balance = ix.credits.balance()
22
+ print(balance)
23
+ """
24
+ return self._http.get("/consult/credits")
@@ -0,0 +1,80 @@
1
+ """Recurso OTP."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from .client import HttpClient
9
+
10
+
11
+ class Otp:
12
+ def __init__(self, http: HttpClient):
13
+ self._http = http
14
+
15
+ def send(
16
+ self,
17
+ to: str,
18
+ *,
19
+ message_default: str | None = None,
20
+ from_: str | None = None,
21
+ qtd_digits: int | None = None,
22
+ with_text: bool | None = None,
23
+ expires_in: int | None = None,
24
+ ) -> dict[str, Any]:
25
+ """
26
+ Envia um código OTP via SMS.
27
+
28
+ A Integrax gera o código automaticamente e substitui o placeholder [code].
29
+
30
+ Args:
31
+ to: Número destino (ex: "5511999999999").
32
+ message_default: Mensagem com placeholder [code]. Padrão: "Seu código: [code]".
33
+ from_: Shortcode de envio. Se omitido, usa o padrão da conta.
34
+ qtd_digits: Total de caracteres no código (padrão: 6).
35
+ with_text: True = alfanumérico, False = só números (padrão: False).
36
+ expires_in: Minutos até expirar o código (padrão: 10).
37
+
38
+ Exemplo::
39
+
40
+ # Envio mínimo (usa todos os defaults)
41
+ ix.otp.send("5511999999999")
42
+
43
+ # Personalizado
44
+ ix.otp.send(
45
+ "5511999999999",
46
+ message_default="Use [code] pra confirmar",
47
+ from_="29094",
48
+ qtd_digits=5,
49
+ with_text=True,
50
+ expires_in=5,
51
+ )
52
+ """
53
+ body: dict[str, Any] = {"to": to}
54
+ if message_default is not None:
55
+ body["message_default"] = message_default
56
+ if from_ is not None:
57
+ body["from"] = from_
58
+ if qtd_digits is not None:
59
+ body["qtd_digits"] = qtd_digits
60
+ if with_text is not None:
61
+ body["with_text"] = with_text
62
+ if expires_in is not None:
63
+ body["expires_in"] = expires_in
64
+ return self._http.post("/send-otp", body)
65
+
66
+ def verify(self, code: str, phone: str) -> dict[str, Any]:
67
+ """
68
+ Valida um código OTP digitado pelo usuário.
69
+
70
+ Args:
71
+ code: Código digitado pelo usuário.
72
+ phone: Número que recebeu o SMS.
73
+
74
+ Exemplo::
75
+
76
+ res = ix.otp.verify("1MP5L", "5511999999999")
77
+ if res["status"] == "verified":
78
+ print("Código válido!")
79
+ """
80
+ return self._http.post("/verify-otp", {"code": code, "phone": phone})
File without changes
@@ -0,0 +1,74 @@
1
+ """Recurso RCS."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from .client import HttpClient
9
+
10
+
11
+ class Rcs:
12
+ def __init__(self, http: HttpClient):
13
+ self._http = http
14
+
15
+ def send(
16
+ self,
17
+ to: list[str],
18
+ message: str,
19
+ from_: str,
20
+ *,
21
+ rcs_type: str | None = None,
22
+ rcs_message: dict[str, Any] | None = None,
23
+ ) -> dict[str, Any]:
24
+ """
25
+ Envia mensagem RCS (BASIC ou RICH com card).
26
+
27
+ Args:
28
+ to: Lista de números destino.
29
+ message: Texto da mensagem (fallback ou mensagem BASIC).
30
+ from_: Sender aprovado.
31
+ rcs_type: "BASIC", "RICH" ou "SINGLE".
32
+ rcs_message: Card rico com mídia e botões (obrigatório pra RICH).
33
+
34
+ Exemplo BASIC::
35
+
36
+ ix.rcs.send(
37
+ ["5511999999999"],
38
+ "Olá! Mensagem RCS básica.",
39
+ "IntegraX",
40
+ rcs_type="BASIC",
41
+ )
42
+
43
+ Exemplo RICH::
44
+
45
+ ix.rcs.send(
46
+ ["5511999999999"],
47
+ "Confira nossa oferta!",
48
+ "IntegraX",
49
+ rcs_message={
50
+ "card": {
51
+ "title": "Black Friday",
52
+ "description": "Até 60% OFF.",
53
+ "media": {
54
+ "file": {"url": "https://exemplo.com/banner.png"},
55
+ "height": "MEDIUM",
56
+ },
57
+ "suggestions": [
58
+ {
59
+ "type": "OPEN_URL",
60
+ "text": "Ver ofertas",
61
+ "url": "https://exemplo.com/ofertas",
62
+ "postbackData": "click_ofertas",
63
+ }
64
+ ],
65
+ }
66
+ },
67
+ )
68
+ """
69
+ body: dict[str, Any] = {"to": to, "message": message, "from": from_}
70
+ if rcs_type is not None:
71
+ body["rcsType"] = rcs_type
72
+ if rcs_message is not None:
73
+ body["rcsMessage"] = rcs_message
74
+ return self._http.post("/send-rcs", body)
@@ -0,0 +1,41 @@
1
+ """Recurso SMS."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from .client import HttpClient
9
+
10
+
11
+ class Sms:
12
+ def __init__(self, http: HttpClient):
13
+ self._http = http
14
+
15
+ def send(
16
+ self,
17
+ to: list[str],
18
+ message: str,
19
+ *,
20
+ from_: str | None = None,
21
+ ) -> dict[str, Any]:
22
+ """
23
+ Envia SMS pra um ou mais números.
24
+
25
+ Args:
26
+ to: Lista de números destino (ex: ["5511999999999"]).
27
+ message: Conteúdo da mensagem.
28
+ from_: Shortcode ou sender ID (ex: "29094"). Se omitido, usa o padrão da conta.
29
+
30
+ Exemplo::
31
+
32
+ res = ix.sms.send(["5511999999999"], "Pedido confirmado ✓")
33
+ print(res["data"][0]["messageId"]) # "82816396"
34
+
35
+ # Com shortcode customizado
36
+ res = ix.sms.send(["5511999999999"], "Olá!", from_="29094")
37
+ """
38
+ body: dict[str, Any] = {"to": to, "message": message}
39
+ if from_ is not None:
40
+ body["from"] = from_
41
+ return self._http.post("/send-sms", body)
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: integrax
3
+ Version: 1.0.0
4
+ Summary: Send SMS, RCS & OTP messages via API. Bulk SMS, OTP verification, phone number lookup.
5
+ Author-email: Integrax <contato@integrax.lat>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://integrax.lat
8
+ Project-URL: Documentation, https://integrax.lat/desenvolvedores
9
+ Project-URL: Repository, https://github.com/integrax-lat/integrax-python
10
+ Project-URL: Create Account, https://integrax.app
11
+ Keywords: sms,send-sms,bulk-sms,sms-api,rcs,otp,otp-verification,verify-phone,phone-verification,messaging,cpaas,text-message,integrax,api
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Typing :: Typed
21
+ Classifier: Topic :: Communications
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: httpx>=0.25.0
27
+ Dynamic: license-file
28
+
29
+ # integrax
30
+
31
+ SDK oficial da Integrax para Python — SMS, RCS, OTP e consultas via API REST.
32
+
33
+ - Usa [httpx](https://www.python-httpx.org/) como HTTP client
34
+ - Type hints completos (PEP 561 — `py.typed`)
35
+ - Python 3.9+
36
+
37
+ ## Obtendo seu token
38
+
39
+ 1. Crie uma conta gratuita em [integrax.app](https://integrax.app)
40
+ 2. Após o cadastro, acesse o menu **API** e crie um token
41
+
42
+ Pronto, você já pode integrar!
43
+
44
+ > Se receber `MESSAGE_NOT_ALLOWED`, entre em contato com o suporte pelo [WhatsApp](https://wa.me/551132808396) e solicite a liberação.
45
+
46
+ ## Instalação
47
+
48
+ ```bash
49
+ pip install integrax
50
+ ```
51
+
52
+ ## Quick start
53
+
54
+ ```python
55
+ from integrax import Integrax
56
+
57
+ ix = Integrax("seu-token-aqui")
58
+
59
+ # Enviar SMS
60
+ res = ix.sms.send(["5511999999999"], "Pedido #4821 confirmado ✓")
61
+ print(res["data"][0]["messageId"]) # "82816396"
62
+ ```
63
+
64
+ Ou com context manager:
65
+
66
+ ```python
67
+ with Integrax("seu-token") as ix:
68
+ ix.sms.send(["5511999999999"], "Olá!")
69
+ ```
70
+
71
+ ## Configuração
72
+
73
+ ```python
74
+ ix = Integrax(
75
+ "seu-token",
76
+ base_url="https://sms.aresfun.com", # padrão
77
+ timeout=15.0, # padrão: 30s
78
+ )
79
+ ```
80
+
81
+ ## SMS
82
+
83
+ ```python
84
+ # Envio simples (usa shortcode padrão da conta)
85
+ res = ix.sms.send(["5511999999999", "5521888888888"], "Sua mensagem aqui")
86
+
87
+ # Com shortcode customizado
88
+ res = ix.sms.send(["5511999999999"], "Olá!", from_="29094")
89
+
90
+ # res["code"] == "SMS_SENT"
91
+ # res["data"][0]["status"] == "SENT_TO_OPERATOR"
92
+ # res["data"][0]["messageId"] == "82816396"
93
+ ```
94
+
95
+ ### DLR (webhook)
96
+
97
+ Configure seu webhook para receber o status de entrega:
98
+
99
+ ```python
100
+ # Payload recebido no seu endpoint
101
+ {
102
+ "message_id": "82816396",
103
+ "status": "DELIVRD", # DELIVRD | EXPIRED | REJECTD | UNDELIV
104
+ "number": "5511999999999"
105
+ }
106
+ ```
107
+
108
+ ## OTP
109
+
110
+ Duas chamadas: enviar código e verificar.
111
+
112
+ ```python
113
+ # 1. Envio mínimo (usa todos os defaults: 6 dígitos numéricos, expira em 10min)
114
+ ix.otp.send("5511999999999")
115
+
116
+ # 1b. Personalizado
117
+ ix.otp.send(
118
+ "5511999999999",
119
+ message_default="Use [code] pra confirmar sua conta", # padrão: "Seu código: [code]"
120
+ from_="29094", # se omitido, usa o padrão da conta
121
+ qtd_digits=5, # padrão: 6
122
+ with_text=True, # alfanumérico (padrão: False = só números)
123
+ expires_in=5, # minutos (padrão: 10)
124
+ )
125
+
126
+ # 2. Verificar código digitado pelo usuário
127
+ res = ix.otp.verify("1MP5L", "5511999999999")
128
+ if res["status"] == "verified":
129
+ print("Código válido!")
130
+ ```
131
+
132
+ ## RCS
133
+
134
+ ### BASIC (só texto)
135
+
136
+ ```python
137
+ ix.rcs.send(
138
+ ["5511999999999"],
139
+ "Olá! Mensagem RCS básica.",
140
+ "IntegraX",
141
+ rcs_type="BASIC",
142
+ )
143
+ ```
144
+
145
+ ### RICH (card com mídia e botões)
146
+
147
+ ```python
148
+ ix.rcs.send(
149
+ ["5511999999999"],
150
+ "Confira nossa oferta!",
151
+ "IntegraX",
152
+ rcs_message={
153
+ "card": {
154
+ "title": "Black Friday",
155
+ "description": "Até 60% OFF em todos os produtos.",
156
+ "media": {
157
+ "file": {"url": "https://exemplo.com/banner.png"},
158
+ "height": "MEDIUM",
159
+ },
160
+ "suggestions": [
161
+ {
162
+ "type": "OPEN_URL",
163
+ "text": "Ver ofertas",
164
+ "url": "https://exemplo.com/ofertas",
165
+ "postbackData": "click_ofertas",
166
+ }
167
+ ],
168
+ }
169
+ },
170
+ )
171
+ ```
172
+
173
+ ## Créditos
174
+
175
+ ```python
176
+ balance = ix.credits.balance()
177
+ print(balance)
178
+ ```
179
+
180
+ ## Consultas
181
+
182
+ ### Por CPF
183
+
184
+ ```python
185
+ res = ix.consult.cpf(["00000000001"], show_phone_valid=True, show_restrictions=True)
186
+ ```
187
+
188
+ ### Por telefone
189
+
190
+ ```python
191
+ res = ix.consult.phone(["551199999999"])
192
+ ```
193
+
194
+ ### Telefone premium (dados enriquecidos)
195
+
196
+ ```python
197
+ res = ix.consult.phone_premium(["551199999999"])
198
+ ```
199
+
200
+ ## Números internacionais
201
+
202
+ - Para números de outros países, insira `+` na frente do número (ex: `+34992000000`).
203
+ - Para envios internacionais, é necessário solicitar a ativação da rota através do suporte.
204
+ - Alguns países permitem `from` personalizado. Se permitido, basta informar o `from` no payload.
205
+
206
+ ## Tratamento de erros
207
+
208
+ ```python
209
+ from integrax import Integrax, IntegraxError
210
+
211
+ try:
212
+ ix.sms.send(["551100000000"], "teste")
213
+ except IntegraxError as e:
214
+ print(e.status) # HTTP status (ex: 401, 422)
215
+ print(e.code) # código da API
216
+ print(e.body) # corpo completo da resposta
217
+ ```
218
+
219
+ ## Licença
220
+
221
+ MIT
@@ -0,0 +1,16 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/integrax/__init__.py
5
+ src/integrax/client.py
6
+ src/integrax/consult.py
7
+ src/integrax/credits.py
8
+ src/integrax/otp.py
9
+ src/integrax/py.typed
10
+ src/integrax/rcs.py
11
+ src/integrax/sms.py
12
+ src/integrax.egg-info/PKG-INFO
13
+ src/integrax.egg-info/SOURCES.txt
14
+ src/integrax.egg-info/dependency_links.txt
15
+ src/integrax.egg-info/requires.txt
16
+ src/integrax.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ httpx>=0.25.0
@@ -0,0 +1 @@
1
+ integrax