| Crates.io | paytour |
| lib.rs | paytour |
| version | 0.1.3 |
| created_at | 2025-12-09 14:37:29.465985+00 |
| updated_at | 2025-12-10 22:22:37.595738+00 |
| description | Cliente Rust para autenticação e consumo da API Paytour (login e passeios) |
| homepage | |
| repository | https://github.com/nextlw/cratesIO |
| max_upload_size | |
| id | 1975583 |
| size | 646,041 |
Crate inspirado na arquitetura do clickup para consumir a API Paytour.
A biblioteca oferece suporte completo para:
cargo add paytour --git https://github.com/nextlw/cratesIO --package paytour
| Variável | Descrição |
|---|---|
PAYTOUR_API_BASE_URL |
URL base (default https://api.paytour.com.br/v2) |
PAYTOUR_LOJA_ID |
Identificador da loja (opcional) |
PAYTOUR_EMAIL |
E-mail do usuário Paytour |
PAYTOUR_PASSWORD |
Senha do usuário |
PAYTOUR_APP_KEY |
Chave de aplicativo |
PAYTOUR_APP_SECRET |
Segredo de aplicativo |
PAYTOUR_ACCESS_TOKEN |
Preenchido automaticamente após login |
PAYTOUR_REFRESH_TOKEN |
Preenchido automaticamente após login |
Defina pelo menos um conjunto de credenciais (usuário ou aplicativo). O login segue o fluxo descrito na documentação oficial (POST /loja/login com Authorization: Basic base64(email:senha) ou app_key:app_secret). Referência: Login Paytour.
use paytour::{
auth::{AuthStrategy, PaytourAuthenticator},
client::{PaytourClient, PasseioQuery},
config::EnvManager,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenv::dotenv().ok();
env_logger::init();
let env = EnvManager::load()?;
let authenticator = PaytourAuthenticator::new(&env);
let token = authenticator.authenticate(env.auth_strategy()).await?;
let client = PaytourClient::new(env.api_base_url.clone(), token.access_token);
let passeios = client.list_passeios(&PasseioQuery::default()).await?;
println!("Total de passeios: {}", passeios.itens.len());
Ok(())
}
use paytour::client::{PaytourClient, PasseioQuery};
// Listar todos os passeios de uma página específica
let query = PasseioQuery::default()
.pagina(1)
.quantidade(50)
.busca("buggy")
.destino_id("123")
.intervalo_datas("2025-01-01", "2025-01-31")
.minimal_response(false);
let response = client.list_passeios(&query).await?;
// Percorrer todas as páginas automaticamente
let todos_passeios = client.list_all_passeios(&query).await?;
println!("Total acumulado: {}", todos_passeios.len());
use paytour::client::PaytourClient;
// Buscar detalhes com disponibilidade estendida (até 12 meses)
let detalhe = client
.get_passeio_detail(2527834, Some(12))
.await?;
println!("Detalhes: {}", serde_json::to_string_pretty(&detalhe)?);
use paytour::client::PaytourClient;
// Obter dias disponíveis para um passeio em um mês/ano específico
let dias = client.get_dias_disponiveis(42, 9, 2025).await?;
println!("Dias disponíveis em setembro/2025: {:?}", dias);
// Retorna: ["2025-09-05", "2025-09-12", "2025-09-19", ...]
// Obter horários disponíveis para um dia específico
let horarios = client.get_horarios_disponiveis(42, "2025-09-05").await?;
println!("Horários: {}", serde_json::to_string_pretty(&horarios)?);
// Obter faixas etárias disponíveis para um dia específico
let faixas = client.get_faixas_etarias(42, "2025-09-05").await?;
println!("Faixas etárias: {}", serde_json::to_string_pretty(&faixas)?);
use paytour::client::{PaytourClient, ComboQuery};
let query = ComboQuery::default()
.pagina(1)
.quantidade(20)
.busca("trem")
.intervalo_datas("2025-01-01", "2025-01-31");
let combos = client.list_combos(&query).await?;
println!("Combos encontrados: {}", combos.itens.len());
use paytour::client::{PaytourClient, AtividadeQuery};
// Listar atividades por intervalo de datas
let query = AtividadeQuery::default()
.intervalo_datas("2025-11-18", "2025-11-18");
let atividades = client.list_atividades(&query).await?;
for atividade in atividades.itens {
println!(
"Voucher: {} | Cliente: {} | Utilizado: {}",
atividade.voucher.as_deref().unwrap_or("-"),
atividade.atividade_cliente_nome.as_deref().unwrap_or("-"),
if atividade.utilizado.unwrap_or(false) { "✓" } else { "✗" }
);
}
// Buscar atividades de um pedido específico
let query_pedido = AtividadeQuery::default()
.pedido_id("3820377");
let atividades_pedido = client.list_atividades(&query_pedido).await?;
// Detalhar uma atividade pelo voucher
let detalhe = client
.get_atividade_detail("123373820377769161341")
.await?;
// Registrar check-in
let check_in = client
.check_in_atividade("123373820377769161341", Some("MyApp".to_string()))
.await?;
use paytour::client::{PaytourClient, CupomQuery};
use serde_json::json;
// Listar todos os cupons
let query = CupomQuery::new()
.page(1)
.per_page(20);
let cupons = client.list_cupons(&query).await?;
println!("Cupons encontrados: {}", cupons.itens.len());
// Buscar um cupom específico pelo código
let query_cupom = CupomQuery::new()
.cupom("CARNAVAL10")
.page(1)
.per_page(1);
let resultado = client.list_cupons(&query_cupom).await?;
// Criar um novo cupom
let novo_cupom = json!({
"codigo": "TESTE10",
"tipo": "percentual",
"valor": 10.0,
"valido_de": "2025-01-01",
"valido_ate": "2025-12-31"
});
let cupom_criado = client.create_cupom(&novo_cupom).await?;
// Atualizar um cupom existente
let atualizacao = json!({
"valor": 15.0
});
let cupom_atualizado = client.update_cupom(42, &atualizacao).await?;
// Apagar um cupom
client.delete_cupom(42).await?;
// Validar um cupom e obter o desconto
let validacao = json!({
"cupom": "CARNAVAL10",
"itens": [
{
"passeio_id": 2527834,
"quantidade": 2,
"preco": 100.0
}
]
});
let resultado_validacao = client.validate_cupom(&validacao).await?;
// Extrair valores de desconto
let desconto_com = resultado_validacao
.get("_desconto_sobre_total_com_desconto_por_metodo_de_pagamento")
.and_then(|v| v.as_f64());
let desconto_sem = resultado_validacao
.get("_desconto_sobre_total_sem_desconto_por_metodo_de_pagamento")
.and_then(|v| v.as_f64());
println!("Desconto (com método): R${:.2}", desconto_com.unwrap_or(0.0));
println!("Desconto (sem método): R${:.2}", desconto_sem.unwrap_or(0.0));
use paytour::client::{DestinoQuery, PaytourClient};
// Nota: Destinos não requerem autenticação
let client = PaytourClient::new(api_base_url, String::new());
// Listar todos os destinos
let query = DestinoQuery::new().page(1);
let destinos = client.list_destinos(&query).await?;
// Buscar destinos por nome/cidade/estado
let query_busca = DestinoQuery::new()
.page(1)
.busca("Natal");
let destinos_busca = client.list_destinos(&query_busca).await?;
// Buscar destinos por localização (latitude/longitude)
let query_local = DestinoQuery::new()
.page(1)
.localizacao("-5.79448", "-35.211")
.range(100); // 100 metros de raio
let destinos_local = client.list_destinos(&query_local).await?;
// Detalhar um destino específico
let detalhe = client.get_destino_detail(42).await?;
use paytour::client::{CarrinhoQuery, PaytourClient};
// Listar carrinhos da loja
let query = CarrinhoQuery::new()
.page(1)
.per_page(20);
let carrinhos = client.list_carrinhos(&query).await?;
// Detalhar um carrinho específico
let detalhe = client.get_carrinho_detail(42).await?;
// Criar um novo carrinho (form-data)
let form_data = vec![
("passeio_id", "2527834"),
("quantidade", "2"),
("data", "2025-01-15"),
("faixa_etaria_id", "1"),
("valido_ate", "2025-01-15 23:59:59"),
];
let carrinho = client.create_carrinho(&form_data).await?;
// Apagar um carrinho
client.delete_carrinho(42).await?;
use paytour::client::{PedidoQuery, PaytourClient};
// Listar pedidos da loja com filtros
let query = PedidoQuery::new()
.page(1)
.per_page(30)
.include_items(true)
.include_logs_status(true)
.include_obs(true)
.created_at_min("2022-03-28 00:00:00")
.created_at_max("2022-04-01 23:59:59");
let pedidos = client.list_pedidos(&query).await?;
// Detalhar um pedido específico
let detalhe = client.get_pedido_detail(42).await?;
// Criar um novo pedido (form-data)
let form_data = vec![
("cliente_nome", "João Silva"),
("cliente_email", "joao@example.com"),
("cliente_telefone", "84999999999"),
("cliente_cpf", "12345678900"),
("metodo_pagamento", "PAYMENT_LINK"),
// ... outros campos do pedido
];
let pedido = client.create_pedido(&form_data).await?;
// Atualizar o status de um pedido (ex: aprovar)
let pedido_atualizado = client.update_pedido_status(5496, "aprovado").await?;
use paytour::client::PaytourClient;
// Listar todos os ícones disponíveis
let icones = client.list_icones().await?;
for icone in icones.itens {
println!("Ícone: {} | URL: {}",
icone.nome.unwrap_or_default(),
icone.url.unwrap_or_default()
);
}
use paytour::client::{FotosService, FotoUpdateRequest};
// Criar serviço de fotos
let fotos_service = FotosService::new(api_base_url, token);
// Listar fotos de um passeio
let fotos = fotos_service.list_fotos(42).await?;
for foto in fotos.itens {
println!("Foto ID: {:?} | URL: {}",
foto.id,
foto.url.unwrap_or_default()
);
}
// Criar uma nova foto
let request = serde_json::json!({
"url": "https://example.com/foto.jpg"
});
let nova_foto = fotos_service.create_foto(42, &request).await?;
// Editar uma foto
let update_request = FotoUpdateRequest::new()
.posicao(1)
.visivel_site(true)
.capa(false);
let foto_atualizada = fotos_service.update_foto(42, 123, &update_request).await?;
// Reordenar fotos
let foto_ids = vec![3, 1, 2, 4];
let fotos_reordenadas = fotos_service.reordenar_fotos(42, &foto_ids).await?;
// Apagar uma foto
fotos_service.delete_foto(42, 123).await?;
# Login usando credenciais do .env
cd paytour
cargo run --bin paytour-cli -- login
# Refresh token (renovar token expirado)
cargo run --bin paytour-cli -- refresh
# Listar passeios (página 1, 10 itens)
cargo run --bin paytour-cli -- passeios --pagina 1 --quantidade 10
# Listar todos os passeios de todas as páginas
cargo run --bin paytour-cli -- passeios --todas
# Buscar passeios com filtros
cargo run --bin paytour-cli -- passeios \
--pagina 1 \
--quantidade 50 \
--busca "buggy" \
--destino-id "123" \
--data-de "2025-01-01" \
--data-ate "2025-01-31" \
--minimal-response
# Exibir resposta completa em JSON
cargo run --bin paytour-cli -- passeios --pagina 1 --verbose
# Detalhar um passeio específico
cargo run --bin paytour-cli -- passeio-detalhe \
--id 2527834 \
--disponibilidade-ate 12 \
--verbose
# Obter dias disponíveis para um passeio em um mês/ano
cargo run --bin paytour-cli -- passeio-dias \
--id 42 \
--mes 9 \
--ano 2025 \
--verbose
# Obter horários disponíveis para um dia específico
cargo run --bin paytour-cli -- passeio-horarios \
--id 42 \
--dia "2025-09-05" \
--verbose
# Obter faixas etárias disponíveis para um dia específico
cargo run --bin paytour-cli -- passeio-faixas-etarias \
--id 42 \
--dia "2025-09-05" \
--verbose
# Listar combos
cargo run --bin paytour-cli -- combos \
--pagina 1 \
--quantidade 50 \
--busca "trem" \
--data-de "2025-01-01" \
--data-ate "2025-01-31" \
--verbose
# Listar atividades por intervalo de datas
cargo run --bin paytour-cli -- atividades \
--data-de "2025-11-18" \
--data-ate "2025-11-18" \
--verbose
# Listar atividades de um pedido específico
cargo run --bin paytour-cli -- atividades \
--pedido-id "3820377" \
--verbose
# Detalhar uma atividade pelo voucher
cargo run --bin paytour-cli -- atividade-detalhe \
--voucher "123373820377769161341" \
--verbose
# Registrar check-in de uma atividade
cargo run --bin paytour-cli -- atividade-checkin \
--voucher "123373820377769161341" \
--nome-app "MyApp"
# Listar todos os cupons
cargo run --bin paytour-cli -- cupons \
--page 1 \
--per-page 20 \
--verbose
# Buscar um cupom específico pelo código
cargo run --bin paytour-cli -- cupons \
--cupom "CARNAVAL10" \
--page 1 \
--per-page 1 \
--verbose
# Criar um novo cupom
cargo run --bin paytour-cli -- cupom-criar \
--json '{"codigo":"TESTE10","tipo":"percentual","valor":10.0,"valido_de":"2025-01-01","valido_ate":"2025-12-31"}'
# Atualizar um cupom existente
cargo run --bin paytour-cli -- cupom-atualizar \
--id 42 \
--json '{"valor":15.0}'
# Apagar um cupom
cargo run --bin paytour-cli -- cupom-apagar --id 42
# Validar um cupom e obter o desconto
cargo run --bin paytour-cli -- cupom-validar \
--json '{"cupom":"CARNAVAL10","itens":[{"passeio_id":2527834,"quantidade":2,"preco":100.0}]}' \
--verbose
# Listar todos os destinos (não requer autenticação)
cargo run --bin paytour-cli -- destinos \
--page 1 \
--verbose
# Buscar destinos por nome/cidade/estado
cargo run --bin paytour-cli -- destinos \
--page 1 \
--busca "Natal" \
--verbose
# Buscar destinos por localização
cargo run --bin paytour-cli -- destinos \
--page 1 \
--latitude "-5.79448" \
--longitude "-35.211" \
--range 100 \
--verbose
# Detalhar um destino específico
cargo run --bin paytour-cli -- destino-detalhe \
--id 42 \
--verbose
# Listar carrinhos da loja
cargo run --bin paytour-cli -- carrinhos \
--page 1 \
--per-page 20 \
--verbose
# Detalhar um carrinho específico
cargo run --bin paytour-cli -- carrinho-detalhe \
--id 42 \
--verbose
# Apagar um carrinho
cargo run --bin paytour-cli -- carrinho-apagar --id 42
# Criar um novo carrinho (form-data)
cargo run --bin paytour-cli -- carrinho-criar \
--data "passeio_id=2527834,quantidade=2,data=2025-01-15,faixa_etaria_id=1,valido_ate=2025-01-15 23:59:59"
# Listar pedidos da loja
cargo run --bin paytour-cli -- pedidos \
--page 1 \
--per-page 30 \
--include-items \
--include-logs-status \
--include-obs \
--verbose
# Listar pedidos com filtros de data
cargo run --bin paytour-cli -- pedidos \
--page 1 \
--per-page 30 \
--created-at-min "2022-03-28 00:00:00" \
--created-at-max "2022-04-01 23:59:59" \
--updated-at-min "2022-03-28 00:00:00" \
--updated-at-max "2022-04-01 23:59:59" \
--verbose
# Detalhar um pedido específico
cargo run --bin paytour-cli -- pedido-detalhe \
--id 42 \
--verbose
# Criar um novo pedido (form-data)
cargo run --bin paytour-cli -- pedido-criar \
--data "cliente_nome=João Silva,cliente_email=joao@example.com,cliente_telefone=84999999999,cliente_cpf=12345678900,metodo_pagamento=PAYMENT_LINK"
# Atualizar o status de um pedido (ex: aprovar)
cargo run --bin paytour-cli -- pedido-atualizar-status \
--id 5496 \
--status "aprovado"
# Listar todos os ícones disponíveis
cargo run --bin paytour-cli -- icones \
--verbose
# Listar fotos de um passeio
cargo run --bin paytour-cli -- fotos-listar \
--passeio-id 42 \
--verbose
# Cadastrar uma nova foto
cargo run --bin paytour-cli -- foto-criar \
--passeio-id 42 \
--json '{"url":"https://example.com/foto.jpg"}'
# Editar uma foto (posição, visibilidade, capa)
cargo run --bin paytour-cli -- foto-editar \
--passeio-id 42 \
--foto-id 123 \
--posicao 1 \
--visivel-site true \
--capa false
# Apagar uma foto
cargo run --bin paytour-cli -- foto-apagar \
--passeio-id 42 \
--foto-id 123
# Reordenar fotos
cargo run --bin paytour-cli -- fotos-reordenar \
--passeio-id 42 \
--ids "1,2,3,4"
PasseioQuery — Builder para filtrar passeios
.pagina(u32), .quantidade(u32), .busca(String), .destino_id(String).intervalo_datas(String, String), .minimal_response(bool)PasseioListResponse — Resposta com itens: Vec<Passeio>Passeio — Modelo de passeioPasseioDetail — Detalhes completos (tipo Value)HorariosResponse — Resposta de horários disponíveis (tipo flexível)FaixasEtariasResponse — Resposta de faixas etárias disponíveis (tipo flexível)ComboQuery — Builder para filtrar combos
.pagina(u32), .quantidade(u32), .busca(String).intervalo_datas(String, String)ComboListResponse — Resposta com itens: Vec<ComboItem>ComboItem — Modelo de comboAtividadeQuery — Builder para filtrar atividades
.intervalo_datas(String, String), .pedido_id(String)AtividadeListResponse — Resposta com itens: Vec<Atividade>Atividade — Modelo de atividade (voucher, cliente, data, utilizado, etc.)AtividadeDetail — Detalhes completos (tipo Value)CheckInResponse — Resposta do check-inCupomQuery — Builder para filtrar cupons
.cupom(String), .page(u32), .per_page(u32) (máximo 100)CupomListResponse — Resposta com itens: Vec<Cupom>Cupom — Modelo de cupom (id, codigo, descricao, tipo, valor)CupomDetail — Detalhes completos (tipo Value)CupomValidateResponse — Resposta da validação com campos de desconto (tipo Value)CupomCreateRequest, CupomUpdateRequest, CupomValidateRequest — Payloads flexíveis (tipo Value)DestinoQuery — Builder para filtrar destinos (não requer autenticação)
.page(u32), .busca(String), .loja_id(u64).localizacao(String, String), .range(u32)DestinoListResponse — Resposta com itens: Vec<Destino>Destino — Modelo de destino (id, nome, cidade, estado, pais)DestinoDetail — Detalhes completos (tipo Value)CarrinhoQuery — Builder para filtrar carrinhos
.page(u32), .per_page(u32) (máximo 100)CarrinhoListResponse — Resposta com itens: Vec<Carrinho>Carrinho — Modelo de carrinho (id, total)CarrinhoDetail — Detalhes completos (tipo Value)PedidoQuery — Builder para filtrar pedidos
.page(u32), .per_page(u32) (máximo 100).include_items(bool), .include_logs_status(bool), .include_obs(bool).created_at_min(String), .created_at_max(String).updated_at_min(String), .updated_at_max(String)PedidoListResponse — Resposta com itens: Vec<Pedido>Pedido — Modelo de pedido (id, total, status)PedidoDetail — Detalhes completos (tipo Value)IconeListResponse — Resposta com itens: Vec<Icone>Icone — Modelo de ícone (id, nome, url, categoria)FotosService — Serviço para gerenciar fotos de passeiosFotoListResponse — Resposta com itens: Vec<Foto>Foto — Modelo de foto (id, url, posicao, visivel_site, capa)FotoDetail — Detalhes completos (tipo Value)FotoCreateRequest — Payload para criar foto (tipo Value)FotoUpdateRequest — Builder para atualizar foto
.posicao(u32), .visivel_site(bool), .capa(bool)PaytourClient// Passeios
client.list_passeios(&query) -> Result<PasseioListResponse>
client.list_all_passeios(&query) -> Result<Vec<Passeio>>
client.get_passeio_detail(id, disponibilidade_ate) -> Result<PasseioDetail>
client.get_dias_disponiveis(id, mes, ano) -> Result<Vec<String>>
client.get_horarios_disponiveis(id, dia) -> Result<HorariosResponse>
client.get_faixas_etarias(id, dia) -> Result<FaixasEtariasResponse>
// Combos
client.list_combos(&query) -> Result<ComboListResponse>
// Atividades
client.list_atividades(&query) -> Result<AtividadeListResponse>
client.get_atividade_detail(voucher_code) -> Result<AtividadeDetail>
client.check_in_atividade(voucher_code, nome_app) -> Result<CheckInResponse>
// Cupons
client.list_cupons(&query) -> Result<CupomListResponse>
client.create_cupom(&request) -> Result<CupomDetail>
client.update_cupom(id, &request) -> Result<CupomDetail>
client.delete_cupom(id) -> Result<()>
client.validate_cupom(&request) -> Result<CupomValidateResponse>
// Destinos (não requer autenticação)
client.list_destinos(&query) -> Result<DestinoListResponse>
client.get_destino_detail(id) -> Result<DestinoDetail>
// Carrinhos
client.list_carrinhos(&query) -> Result<CarrinhoListResponse>
client.get_carrinho_detail(id) -> Result<CarrinhoDetail>
client.delete_carrinho(id) -> Result<()>
client.create_carrinho(&form_data) -> Result<CarrinhoDetail>
// Pedidos
client.list_pedidos(&query) -> Result<PedidoListResponse>
client.get_pedido_detail(id) -> Result<PedidoDetail>
client.create_pedido(&form_data) -> Result<PedidoDetail>
client.update_pedido_status(id, status) -> Result<PedidoDetail>
// Ícones
client.list_icones() -> Result<IconeListResponse>
// Fotos de Passeios (via FotosService)
let fotos_service = FotosService::new(api_base_url, token);
fotos_service.list_fotos(passeio_id) -> Result<FotoListResponse>
fotos_service.create_foto(passeio_id, &request) -> Result<FotoDetail>
fotos_service.update_foto(passeio_id, foto_id, &request) -> Result<FotoDetail>
fotos_service.delete_foto(passeio_id, foto_id) -> Result<()>
fotos_service.reordenar_fotos(passeio_id, &foto_ids) -> Result<FotoListResponse>
# Executar todos os testes
cargo test
# Executar testes específicos
cargo test pedido_query_translates_params
cargo test query_builder_translates_params
Contribuições são bem-vindas! Por favor:
git checkout -b feature/nova-funcionalidade)git commit -am 'Adiciona nova funcionalidade')git push origin feature/nova-funcionalidade)Este projeto está licenciado sob a Licença Apache 2.0 - veja o arquivo LICENSE para detalhes.
app_key/app_secret)refresh_tokenclickup