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.