
Security News
NVD Quietly Sweeps 100K+ CVEs Into a “Deferred” Black Hole
NVD now marks all pre-2018 CVEs as "Deferred," signaling it will no longer enrich older vulnerabilities, further eroding trust in its data.
Esta SDK foi desenvolvida para abstrair aos desenvolvedores os principais detalhes da comunicação com API v2 da Juno tanto em produção quanto em ambiente sandbox.
Você pode acessar a documentação base da api aqui: Api V2 Juno.
Instalação utilizando Pip
pip install junopy
Git/Clone
git clone https://github.com/robertons/junopy
cd junopy
pip install -r requirements.txt
python setup.py install
Os objetos neste SDK podem ser criados em 3 (três) formas distintas a critério do utilizador.
Método 1 - Construção
objeto = Objeto(campo1 = 'valor', campo2 = 'valor 2', campo_datetime = datetime.now(), campo_float = 10.1)
Método 2 - Construção com Dicionário
objeto = Objeto(**{'campo1':'valor', 'campo2':'valor 2', 'campo_datetime':datetime.now(), 'campo_float' = 10.1})
Método 3 - Pós-Construção
objeto = Objeto()
objeto.campo1 = 'valor'
objeto.campo2 = 'valor 2'
objeto.campo_datetime = datetime.now()
objeto.campo_float = 10.1
Método toJSON() retorna os dados do Objeto em formato diciciontario não codificados.
objeto = Objeto(...)
print(objeto.toJSON())
posição | campo | obrigatório | padrão | descrição |
---|---|---|---|---|
1 | private_token | sim | Token Privado Juno | |
2 | clientId | sim | Id Cliente | |
3 | clientSecret | sim | Chave Cliente | |
4 | sandbox | não | False | Ambiente Produção/Sandbox |
5 | debug | não | False | Depuração Request Post, Get, Put, Patch e Delete |
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET', sandbox=True)
Cada token com permissão de acesso ao servidor de serviço tem validade de 1 hora, a recomendação da Juno é que um novo Token seja gerado apenas em caso de expiração. A instancia gerada administra isso automaticamente, contudo a função GetToken permite obter o token para que os dados sejam utilizado em outras instâncias. Este processo não é obrigatório, mas é recomendável principalmente em sistemas onde serão criadas novas instâncias junopy a cada transação
Mais detalhes em Documentação Oficial
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
junopy.GetToken()
token_valido_1h = junopy.TOKEN
É possível definir manualmente os dados de acesso através da função SetToken
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
junopy.SetToken('access_token', 'token_type', 'expires')
Lista de Bancos
bancos = junopy.util.Banks()
Lista de Tipos de Empresas
tipos_empresas = junopy.util.CompanyTypes()
Tipos de Negócios
tipos_empresas = junopy.util.BusinessAreas()
Chave Publica de Criptografia
chave_publica = junopy.util.PublicKey()
Validação Webhook
Todo Webhook recebido da Juno traz consigo uma assinatura no header da Requisição Post
. A assinatura é um hash para validar a autenticidade do conteúdo.
Ao criar um Webhook é gerado uma chave que deve ser armazenada em segurança e utilizada neste processo.
Leia atentamente como funciona o processo em Criação e Assinatura de Webhook
campo | tipo | obrigatório |
---|---|---|
x_signature | string | sim |
body_content | bytes | sim |
secret | string | sim |
o retorno da função será True
ou False
webhook_valido = junopy.util.IsValidWebhook(x_signature, body_content, secret)
A seção compreende:
Mais detalhes em Documentação Oficial
No exemplo abaixo foram utilizados os 3 métodos de criação de objeto de formas distintas:
Após o preenchimento do Objeto o comando Create, realiza o Post na ApiV2.
conta = junopy.DigitalAccount()
conta.name = "Usuário Teste"
conta.document = "123.456.789-00"
conta.email = "usu.teste@email.com"
conta.birthDate = "1980-01-01" #
conta.phone = "9999999999"
conta.businessArea = 2015
conta.linesOfBusiness = "INDIVIDUAL"
conta.address = junopy.Address(**{
'street': 'Nome da Rua',
'number': '01',
'complement': 'Casa',
'neighborhood': 'Bairro',
'city': 'Cidade',
'state': 'UF',
'postCode': '99999999'
})
conta_bancaria = junopy.BankAccount()
conta_bancaria.bankNumber = "000"
conta_bancaria.agencyNumber = "1111"
conta_bancaria.accountNumber = "22334455"
conta_bancaria.accountComplementNumber = "0"
conta_bancaria.accountType = "CHECKING"
conta_bancaria.accountHolder = junopy.AccountHolder(name='Usuario Teste', document='00000000000')
conta.bankAccount = conta_bancaria
conta.Create()
conta = junopy.DigitalAccount(id='dac_E6FECDB17EAC5992').Get()
** Consulta de conta digital criada a partir do token privado da conta digital**
conta_digital_criada = junopy.DigitalAccount(id='dac_E6FECDB17EAC5992', resourceToken='8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9').Get()
conta = junopy.DigitalAccount()
conta.id = "dac_E6FECDB17EAC5992"
conta.resourceToken = '8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9'
conta.address = junopy.Address(
street = 'Nome da Rua',
number = '01',
complement = 'Casa',
neighborhood = 'Bairro',
city = 'Cidade',
state = 'UF',
postCode = '99999999'
})
conta.Update()
Mais detalhes em Documentação Oficial
onboarding = junopy.onboarding.Documents(
returnUrl="https://www.website.com.br/documents",
refreshUrl="https://www.website.com.br/invalid")
onboarding = junopy.onboarding.Account(
referenceId='id_proprio',
returnUrl="https://www.website.com.br/documents",
refreshUrl="https://www.website.com.br/invalid"
)
Mais detalhes em Documentação Oficial
Consulta
documentos_esperados = junopy.Document(id='dac_E6FECDB17EAC5993').Get()
Consulta de outra Conta Digital (Resource)
documentos_esperados = junopy.Document(id='dac_E6FECDB17EAC5992', resourceToken='8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9').Get()
Lista Documentos
documentos_esperados = junopy.Document().Get()
Lista Documentos de outra Conta Digital (Resource)
documentos_esperados = junopy.Document(resourceToken='8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9').Get()
Método path do arquivo Uma array de string contendo o caminho local do arquivo
documentos_esperados = junopy.Document(
id='doc_AD1E698AB61CF185',
resourceToken='8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9').SendFiles(['arquivo_1.pdf', 'arquivo_2.pdf'])
Método BufferedReader do arquivo Uma array com tuplas onde posição 0 é o nome do arquivo e posição 1 os BufferedReader
documentos_esperados = junopy.Document(
id='doc_AD1E698AB61CF185', resourceToken='8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9').SendFiles([('arquivo_1.pdf', file_buffered)])
Método bytes do arquivo Uma array com tuplas onde posição 0 é o nome do arquivo e posição 1 os bytes
documentos_esperados = junopy.Document(
id='doc_AD1E698AB61CF185', resourceToken='8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9').SendFiles([('arquivo_1.pdf', file_bytes)])
Mais detalhes em Documentação Oficial
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
saldo = junopy.Balance()
{'balance': 0.0, 'withheldBalance': 0.0, 'transferableBalance': 0.0}
ou de outra conta digital
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
saldo = junopy.Balance(resourceToken = '8A596ED1DEB738091FDE8AF11CCD6E7730970A95503AB32CEA340FAB190139C9')
Mais detalhes em Documentação Oficial
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
transfer = junopy.transfers.Default(100.0)
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
#P2P(name:str, document:str, amount:float, accountNumber:str)
transfer = junopy.transfers.P2P('Nome', 'CPF/CNPJ', 100.0, 'NUMERO_CONTA_2P')
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
#Bank(name:str, document:str, amount:float, bank:BankAccount)
conta_bancaria = junopy.BankAccount()
conta_bancaria.bankNumber = "000"
conta_bancaria.agencyNumber = "1111"
conta_bancaria.accountNumber = "22334455"
conta_bancaria.accountComplementNumber = "0"
conta_bancaria.accountType = "CHECKING"
transfer = junopy.transfers.Bank('Nome', 'CPF/CNPJ', 100.0, conta_bancaria)
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
#Pix(name:str, document:str, amount:float, bank:BankAccount)
transfer = junopy.transfers.Pix('Nome', 'CPF/CNPJ', 100.0, junopy.BankAccount(
ispb='0000000',
bankNumber="000",
agencyNumber="1111",
accountNumber="22334455",
accountComplementNumber="0",
accountType="SAVINGS"
}))
Mais detalhes em Documentação Oficial
Retorna uma lista de objetos EventType
Tipo de Evento | Descrição |
---|---|
DIGITAL_ACCOUNT_STATUS_CHANGED | Mudanças de status de uma conta digital |
DIGITAL_ACCOUNT_CREATED | Confirmação de criação de uma conta digital - Válido somente para a solução Whitelabel |
DOCUMENT_STATUS_CHANGED | Mudanças de status de um documento da conta digital |
TRANSFER_STATUS_CHANGED | Mudanças de status de uma transferência |
P2P_TRANSFER_STATUS_CHANGED | Mudanças de status de uma transferência P2P |
CHARGE_STATUS_CHANGED | Mudanças de status de uma cobrança emitida |
CHARGE_READ_CONFIRMATION | Confirmação de leitura/visualização de uma cobrança |
PAYMENT_NOTIFICATION | Pagamento de uma cobranças |
import junopy
events = junopy.EventTypes()
Mais detalhes em Documentação Oficial
Cria e retorna um objeto Webhook
import junopy
junopy.Juno('PRIVATE_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET')
#Webhook().Create(url:str, eventTypes:list)
webhook = junopy.Webhook().Create("https://url.segura_recebe_notificacao.com", ["DIGITAL_ACCOUNT_CREATED", "DIGITAL_ACCOUNT_STATUS_CHANGED"])
webhooks = junopy.Webhooks()
webhooks = junopy.Webhook(id='wbh_6D7EF263A2755055').Get()
#Webhook().Update(status:str, eventTypes:list)
webhook = junopy.Webhook(id='wbh_6D7EF263A2755055').Update("INACTIVE", ["DIGITAL_ACCOUNT_CREATED", "DIGITAL_ACCOUNT_STATUS_CHANGED"])
webhook = junopy.Webhook(id='wbh_6D7EF263A2755055').Delete()
Mais detalhes em Documentação Oficial
cobranca = junopy.charges.Create(
junopy.Charge(
description = 'Cobrança Teste',
amount = 10.0,
paymentTypes = ['BOLETO', 'CREDIT_CARD']
),
junopy.Billing(
name = 'Nome do Usuário',
document = 'CPF',
email = 'email',
address = junopy.Address(
street= 'Rua',
number='Numero',
complement='Complemento',
neighborhood='Bairro',
city='Cidade',
state='UF',
postCode='99999999'
),
phone = '99999199999',
notify = False
)
)
O Retorno será uma lista objeto ChargeResource
É possível realizar buscas utilizando filtros, veja na documentação oficial: (Documentação)
Devolve 20 cobranças por páginas, podendo ser estendido até 100 páginas com pageSize=100
.
busca = junopy.charges.Search()
ou
busca = junopy.charges.Search(pageSize=100)
ou
busca = junopy.charges.Search(createdOnStart='2021-07-10')
A partir da primeira busca é possível navegar pelas páginas superiores/inferiores através dos métodos Next
e Previous
Para avançar:
proxima = junopy.charges.Next()
Para voltar:
anterior = junopy.charges.Previous()
cobranca = junopy.charges.Get(id="chr_8C87D875719FE478195F5AE32309F77B")
junopy.charges.Cancel(id="chr_8C87D875719FE478195F5AE32309F77B")
junopy.charges.SetSplit(id="chr_8C87D875719FE478195F5AE32309F77B", split=[
junopy.Split(
recipientToken = "Token",
amount = 10.0,
amountRemainder = True,
chargeFee= True),
junopy.Split(
recipientToken = "Token2",
amount = 10.0,
amountRemainder = False,
chargeFee= True)
])
Mais detalhes em Documentação Oficial
cartao_credito = junopy.creditcard.Tokenize(hash="0210da66-6c54-4f3b-9e95-9e044be38d79")
Mais detalhes em Documentação Oficial
# CRIAÇÃO DE COBRANÇA
cobranca = junopy.charges.Create(
junopy.Charge(
description = 'Produto Exemplo',
amount = 340.0,
paymentTypes = ['CREDIT_CARD']
),
junopy.Billing(
name = 'Usuario Teste',
document = 'cpf',
email = 'usuario@email.com.br',
address = junopy.Address(
street = 'Endereco',
number = 'Numero',
complement = 'Complemento',
neighborhood = 'Bairro',
city = 'Cidade',
state = 'UF',
postCode = '99999999'),
phone = '99999999999',
notify = False
)
)
# PROCESSAMENTO DE PAGAMENTO
if len(cobranca) > 0:
pagamento = junopy.payment.Create(
chargeId = cobranca[0].id,
creditcard = junopy.CreditCard(
creditCardId = '9a453d71-3ec1-44a5-b2f3-0596ced42a35'
),
billing = junopy.Billing(
name = 'Usuario Teste',
email = 'usuario@email.com.br',
address = junopy.Address(
street = 'Endereco',
number = 'Numero',
complement = 'Complemento',
neighborhood = 'Bairro',
city = 'Cidade',
state = 'UF',
postCode = '99999999'),
delayed = False
)
)
Mais detalhes em Documentação Oficial
estorno = junopy.payment.Refund(paymentId='pay_BDBBF5F40B8B94F23DB2117904EB4B08')
estorno = junopy.payment.Refund(paymentId='pay_BDBBF5F40B8B94F23DB2117904EB4B08', amount=40.00)
estorno = junopy.payment.Refund(paymentId='pay_BDBBF5F40B8B94F23DB2117904EB4B08', amount=40.00, split=[
junopy.Split(
recipientToken="Token",
amount=10.0,
amountRemainder=True,
chargeFee=True),
junopy.Split(
recipientToken="Token2",
amount=10.0,
amountRemainder=False,
chargeFee=True)])
Mais detalhes em Documentação Oficial
captura = junopy.payment.Capture(paymentId='pay_BDBBF5F40B8B94F23DB2117904EB4B08')
captura = junopy.payment.Capture(paymentId='pay_BDBBF5F40B8B94F23DB2117904EB4B08', amount=100.00)
plano = junopy.Plan(name="Plano Teste", amount=100.00).Create()
plano = junopy.Plan(id='pln_76A6AC4929EF068B').Get()
planos = junopy.Plan().Get()
plano = junopy.Plan(id='pln_76A6AC4929EF068B').Deactivate()
plano = junopy.Plan(id='pln_76A6AC4929EF068B').Reactivate()
assinatura = junopy.Subscription(
dueDay=10,
planId='pln_76A6AC4929EF068B',
chargeDescription='Assinatura Recorrente Plano de Teste',
creditCardDetails=junopy.CreditCard(
creditCardId='9a453d71-3ec1-44a5-b2f3-0596ced42a35'
),
billing=junopy.Billing(
name='Usuario Teste',
document='cpf',
email='usuario@email.com.br',
address=junopy.Address(
street='Rua',
number='numero',
complement='completemento',
neighborhood='bairro',
city='cidade',
state='UF',
postCode='99999999')),
notify=False
).Create()
assinatura = junopy.Subscription(id='sub_EDA3F6CA13DFEC4C').Get()
assinaturas = junopy.Subscription().Get()
assinatura = junopy.Subscription(id='sub_EDA3F6CA13DFEC4C').Deactivate()
assinatura = junopy.Subscription(id='sub_EDA3F6CA13DFEC4C').Reactivate()
assinatura = junopy.Subscription(id='sub_EDA3F6CA13DFEC4C').Cancel()
assinatura = junopy.Subscription(id='sub_EDA3F6CA13DFEC4C').Complete()
pagamento_conta = junopy.Bill(
numericalBarCode="00190500954014481606906809350314337370000001000",
paymentDescription="Boleto Bancário",
beneficiaryDocument="CPF/CNPJ",
dueDate="2021-07-12",
paymentDate="yyyy-MM-dd",
billAmount=10.00,
paidAmount=10.00,
).Create()
# CHAVE GERADA UMA ÚNICA VEZ
uudi = str(uuid.uuid4())
pix = junopy.pix.Keys(idempotency=uudi)
pix = junopy.pix.StaticQRCode(
idempotency='d63313cd-d01a-4091-b352-182a0a96baca',
key='06c4e6fe-48cb-4263-89a3-c8bc342ce65e',
includeImage=True,
amount=100.00,
reference='Teste de Pix',
additionalData='Teste de Pix com Dados Adicionais')
EM DESENVOLVIMENTO
Em caso de dúvidas, problemas ou sugestões: falecom@juno.com.br
Veja em CHANGELOG para maiores informações sobre as mudanças recentes
As contribuições por meio de Pull Requests
são bem-vindas e serão totalmente creditadas.
Se você descobrir qualquer problema relacionado à segurança, envie um e-mail para robertonsilva@gmail.com
Veja em LICENÇA para maiores informações sobre a licença de uso.
FAQs
SDK Python3 para Integração com Juno API V2
We found that junopy demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
NVD now marks all pre-2018 CVEs as "Deferred," signaling it will no longer enrich older vulnerabilities, further eroding trust in its data.
Research
Security News
Lazarus-linked threat actors expand their npm malware campaign with new RAT loaders, hex obfuscation, and over 5,600 downloads across 11 packages.
Security News
Safari 18.4 adds support for Iterator Helpers and two other TC39 JavaScript features, bringing full cross-browser coverage to key parts of the ECMAScript spec.