Search by

risetechapps / orchestrator-link-for-laravel

risetechapps

Cliente Laravel da API Orchestrator da RiseTech.

Package info

github.com/risetechapps/orchestrator-link-for-laravel

pkg:composer/risetechapps/orchestrator-link-for-laravel

Statistics

Installs: 51

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.4 2026-10-26 18:08 UTC

This package is auto-updated.

Last update: 2026-10-26 18:08:33 UTC


README

Package Laravel para comunicação com a API Orchestrator da RiseTech. Fornece acesso a dados de CPF, CNPJ (com sócios e Simples/MEI), CNAE, CEP, código IBGE, geolocalização, bancos, países, estados, cidades, clima, feriados, calendário, WHOIS, FIPE, câmbio, ações B3, indicadores do Banco Central, PIX copia e cola, NCM (com tributos), validação de e-mail e telefone, e frete white label (cotação, envio, PIX, etiqueta e rastreio).

Instalação

composer require risetechapps/orchestrator-link-for-laravel

Configuração

Token de acesso

Adicione ao seu .env:

ORCHESTRATOR_TOKEN=seu_token_aqui

# Opcional: outro ambiente (homologação, túnel local...). Padrão: produção.
ORCHESTRATOR_URL=https://orchestrator.app.br/api/v1/services

A chave de teste da conta também funciona: no frete, ela cria envios de teste (sandbox), sem cobrança real.

Publicar config (opcional)

php artisan vendor:publish --tag=config

Isso cria config/orchestrator-link.php:

return [
    'token' => env('ORCHESTRATOR_TOKEN', ''),
    'url'   => env('ORCHESTRATOR_URL', 'https://orchestrator.app.br/api/v1/services'),
];

Migration (Shipping)

A migration é carregada automaticamente. Para rodar:

php artisan migrate

Para publicar e personalizar:

php artisan vendor:publish --tag=orchestrator-link-migrations

Rotas proxy (opcional)

Para expor os endpoints como proxy na sua aplicação:

// routes/web.php ou routes/api.php
\RiseTechApps\OrchestratorLink\OrchestratorLink::routes();

As rotas usam a chave da sua conta no orchestrator. Coloque-as atrás da autenticação da sua app (Route::middleware('auth')->group(...)): sem isso, qualquer visitante consulta com a sua cota e, no frete, vê e cria envios da conta.

As rotas respondem 200 no sucesso e 201 nas criações (envio, remetente, PIX, devolução). A validação responde 422, com o corpo de erro (success: false, status, message, errors). Todas as outras falhas respondem 410 com a mensagem: dado não encontrado (404), conflito (409), fonte de dados fora do ar (503), erro interno do frete (500), orchestrator sem resposta (fora do ar ou ORCHESTRATOR_TOKEN ausente) e erros da sua conta (401, 402, 403, 429), que trazem a mensagem genérica (veja abaixo). No 429, o header Retry-After é repassado. Rota inexistente continua 404.

Isso registra as rotas abaixo no seu app:

Método Rota Serviço
GET /services/cpf/{cpf}/{date?} CPF
GET /services/cnpj/{cnpj} CNPJ
GET /services/zip_code/{zip_code} CEP
GET /services/cnpj/{cnpj}/partners Sócios do CNPJ
GET /services/cnpj/{cnpj}/simples Simples Nacional e MEI
GET /services/cnae/{code} CNAE por código
GET /services/cnae?search= Busca CNAE
GET /services/ibge/cities/{uf}?name= Municípios da UF (código IBGE)
GET /services/ibge/city/{code} Município pelo código IBGE
GET /services/ibge/zip_code/{zip_code} Código IBGE do CEP
GET /services/geo/zip_code/{zip_code} Coordenadas do CEP
GET /services/geo/distance/{from}/{to} Distância entre CEPs
GET /services/banks Bancos
GET /services/countries Países
GET /services/country/{country} Info de país
GET /services/states/{country} Estados
GET /services/states/{country}/{state} Info de estado
GET /services/cities/{country}/{state} Cidades
GET /services/holidays/{year}/{state} Feriados
GET /services/weather/{city}/{country}/{state?} Clima
GET /services/domain/{domain} WHOIS
POST /services/calendar Calendário
GET /services/fipe/{type}/brands Marcas FIPE
GET /services/fipe/{type}/{brand}/models Modelos FIPE
GET /services/fipe/{type}/{brand}/{model}/years Anos FIPE
GET /services/fipe/{type}/{brand}/{model}/{year} Preço FIPE
GET /services/exchange/{from}/{to} Câmbio
GET /services/stocks/{symbol} Ações B3
GET /services/stocks Catálogo da B3
GET /services/indicators Indicadores econômicos
GET /services/indicators/{indicator}?from=&to= Um indicador / série
POST /services/pix/decode PIX copia e cola
GET /services/ncm?search= NCM por descrição (/services/ncm/search também responde)
GET /services/ncm/{code} NCM por código
GET /services/ncm/{code}/taxes?uf= Tributos do NCM (IBPT)
GET /services/email/{email} Validação de e-mail
GET /services/phone/{phone} Validação de telefone
GET /services/shipping/services Serviços de entrega
POST /services/shipping/quotes Cotação
GET /services/shipping/agencies Agências de postagem
GET/POST /services/shipping/senders Remetentes salvos
PUT/DELETE /services/shipping/senders/{id} Altera/remove remetente
GET/POST /services/shipping/shipments Lista/cria envios
GET /services/shipping/shipments/{id} Envio
POST /services/shipping/shipments/{id}/purchase Gera o PIX
GET /services/shipping/shipments/{id}/payment Pagamento
POST /services/shipping/shipments/{id}/payment/simulate Simula pagamento (chave de teste)
POST /services/shipping/shipments/payments Um PIX para vários envios
GET /services/shipping/shipments/payments/{group} Situação do PIX de vários
POST /services/shipping/shipments/{id}/cancel Cancela
POST /services/shipping/shipments/{id}/reverse Devolução
GET /services/shipping/shipments/{id}/tracking Rastreio
GET /services/shipping/shipments/{id}/label Etiqueta (PDF)
GET /services/shipping/shipments/labels?ids= Etiquetas de vários (PDF)
GET/PUT/DELETE /services/shipping/webhook Webhook da conta

Formato de retorno

Todos os métodos do helper orchestrator() retornam:

[
    'success' => true|false,
    'data'    => [...],
    'status'  => 200,                 // HTTP do orchestrator (201 nas criações)
    'message' => 'Operation completed successfully.',  // mensagem do orchestrator, quando houver
]

A message do sucesso traz avisos que importam, como o do setShippingWebhook() (o secret só aparece uma vez). A etiqueta em PDF (getShipmentLabel/getShipmentLabels) volta com data.content, data.content_type e data.filename.

success => false com data => [] é o retorno de qualquer falha — os métodos nunca lançam exceção para não derrubar a request (degradação graciosa). A falha traz também o que o orchestrator respondeu, para mostrar ao usuário:

[
    'success' => false,
    'data'    => [],
    'status'  => 422,                 // HTTP do orchestrator; null sem resposta (conexão, token ausente)
    'message' => 'Dados inválidos.',  // mensagem do orchestrator, quando houver
    'errors'  => ['to.postal_code' => ['O CEP deve ter 8 dígitos.']],  // erros de validação
    'retry_after' => null,            // no 429: segundos até poder tentar de novo
]

Erros da conta. 401 (chave inválida), 402 (serviço fora do plano), 403 (plano expirado, chave sem permissão, chave de teste fora do frete) e 429 (limite ou cota) dizem respeito à sua conta no orchestrator, não ao usuário final da app. Por isso não chegam a ele: o retorno vem com status 503 e message genérica em inglês (Connection::UNAVAILABLE_MESSAGE: This service is temporarily unavailable. Please try again later.), sem errors. O status, o error_code (identificador estável: INVALID_API_KEY, FEATURE_NOT_IN_PLAN, PLAN_EXPIRED, RATE_LIMITED, REQUEST_LIMIT_REACHED...) e o corpo originais vão para o log: error em 401/402/403 e na cota esgotada (REQUEST_LIMIT_REACHED), warning no limite por minuto (RATE_LIMITED). A mesma mensagem genérica vem quando o orchestrator não responde (status null).

Erros da consulta (404 não encontrado, 409, 422, 503 da fonte...) chegam como o orchestrator mandou, com a mensagem dele.

Status comuns: 404 não encontrado, 409 conflito (ex.: etiqueta ainda não pronta), 422 validação, 503 fonte de dados fora do ar, serviço não configurado no servidor ou erro da conta (acima).

Cai nesse retorno quando:

Situação Comportamento Log
Timeout / DNS / conexão recusada errorResponse (não vira HTTP 500) warning
HTTP 5xx (orchestrator quebrado) errorResponse error
HTTP 401/402/403 (chave/plano) e 429 de cota esgotada errorResponse (503 genérico) error (com status, error_code + corpo)
HTTP 4xx (404/422, 429 por minuto...) errorResponse (429 vira 503 genérico) warning (com status + corpo)
ORCHESTRATOR_TOKEN não configurado errorResponse sem sair pra rede error
Corpo não-JSON / shape inesperado success:false, data:[] (não quebra) —

Sempre confira success antes de usar data.

Resiliência (timeouts / retry)

  • connectTimeout 5s + timeout 15s por tentativa — a chamada roda dentro da request web e não prende o worker.
  • Retry só em GET (idempotente) e só em falha de rede: 2 tentativas no total. Resposta 4xx/5xx volta na hora. POST/PUT/PATCH/DELETE não repetem (evita duplicar envio/PIX); para repetir com segurança, use a chave de idempotência (ver Frete).

Cache

Respostas de GET com sucesso são cacheadas por tipo de volatilidade. POST e falhas nunca são cacheados. Invalidação é por TTL (sem flush manual).

TTL Endpoints
30 dias bancos, países, estados, cidades, feriados, FIPE (marcas/modelos/anos/preço), NCM, CEP, CNAE, código IBGE, coordenadas e distância
1 dia CNPJ, sócios, Simples/MEI, tributos do NCM, telefone, serviços de frete
1 hora domínio (WHOIS), indicadores, e-mail, agências de postagem
sem cache CPF, clima, câmbio, ações B3, calendário, PIX e as operações de frete (envios, pagamento, etiqueta, rastreio, remetentes, webhook)

Em ambiente multi-tenant, o cache é isolado por tenant — cada tenant busca o dado uma vez por TTL. Com os TTLs longos, a redundância é desprezível.

CPF

// Com data de nascimento (recomendado para validação)
$result = orchestrator()->getCPF('98765432100', '1990-05-15');

// Sem data
$result = orchestrator()->getCPF('98765432100');

// CPF com pontuação também é aceito (remove automaticamente)
$result = orchestrator()->getCPF('987.654.321-00');

// Resposta
$result['data']['cpf'];         // CPF formatado
$result['data']['name'];        // Nome
$result['data']['status'];      // true = regular
$result['data']['birth_date'];  // Data de nascimento (Y-m-d)

CNPJ

$result = orchestrator()->getCNPJ('33000167000101');

// CNPJ com pontuação também é aceito
$result = orchestrator()->getCNPJ('33.000.167/0001-01');

// CNPJ alfanumérico (emitido pela Receita desde 2026); minúsculas viram maiúsculas
$result = orchestrator()->getCNPJ('12.ABC.345/01DE-35');

// Resposta
$result['data']['corporate_reason'];    // Razão social
$result['data']['fantasy_name'];        // Nome fantasia
$result['data']['status'];              // true = ativa
$result['data']['address'];             // Endereço (zip_code, address, number, district, city, state...)
$result['data']['client']['email'];     // E-mail
$result['data']['client']['cellphone']; // Telefone
// Sócios e Simples/MEI têm consulta própria: getCnpjPartners() e getCnpjSimples()

CEP

$result = orchestrator()->getZipCode('01310100');

// CEP com hífen também é aceito
$result = orchestrator()->getZipCode('01310-100');

// Resposta
$result['data']['zip_code'];  // CEP formatado
$result['data']['address'];   // Logradouro
$result['data']['district'];  // Bairro
$result['data']['city'];      // Cidade
$result['data']['state'];     // Estado (sigla)
$result['data']['country'];   // País

Bancos

$result = orchestrator()->getBanks();

foreach ($result['data'] as $bank) {
    $bank['code']; // Código (ex: 001)
    $bank['name']; // Nome (ex: Banco do Brasil S.A.)
}

Países / Estados / Cidades

// Lista todos os países
$result = orchestrator()->getCountries();

// Info de um país (aceita nome, ISO2 ou ISO3)
$result = orchestrator()->getCountryInfo('BR');
$result = orchestrator()->getCountryInfo('BRA');
$result = orchestrator()->getCountryInfo('Brazil');

// Estados de um país
$result = orchestrator()->getStates('BR');

// Info de um estado específico
$result = orchestrator()->getStateInfo('BR', 'SP');

// Cidades de um estado
$result = orchestrator()->getCities('BR', 'SP');

Feriados

// Feriados de um estado em um ano
$result = orchestrator()->getHolidays('SP', '2026');

foreach ($result['data'] as $holiday) {
    $holiday['date'];  // 2026-01-01
    $holiday['name'];  // Confraternização Universal
    $holiday['type'];  // national / state
}

Clima

// Por cidade e país (ISO 3166-1 alpha-2: BR, GB, US...)
$result = orchestrator()->getWeather('London', 'GB');

// Por cidade, país e estado (recomendado para cidades brasileiras)
$result = orchestrator()->getWeather('São Paulo', 'BR', 'SP');

foreach ($result['data'] as $forecast) {
    $forecast['date'];                    // 2026-05-31
    $forecast['temperature']['max'];      // Temperatura máxima
    $forecast['temperature']['min'];      // Temperatura mínima
    $forecast['condition']['description']; // Descrição (ex: Parcialmente nublado)
    $forecast['rain']['probability'];     // % de chuva
}

Domínio (WHOIS)

// Com ou sem protocolo — ambos são aceitos
$result = orchestrator()->getDomain('risetech.com.br');
$result = orchestrator()->getDomain('https://risetech.com.br');

// Domínio não registrado volta como falha com status 404 (410 na rota proxy)
$result['data']['created'];       // Data de criação
$result['data']['expiration'];    // Data de expiração
$result['data']['name_servers'];  // Nameservers
$result['data']['holder'];        // Titular

Calendário

Combina feriados + previsão do tempo por período.

// Aqui o país vai em ISO 3166-1 alpha-3 (BRA), diferente do clima
$result = orchestrator()->getCalendar(
    country: 'BRA',
    state:   'SP',
    city:    'São Paulo',
    start:   '2026-06-01',
    end:     '2026-06-07'
);

foreach ($result['data'] as $day) {
    $day['date'];     // 2026-06-01
    $day['weather'];  // Dados do clima
    $day['holidays']; // Feriados do dia (ou null)
}

FIPE (Tabela de Veículos)

Tipos disponíveis: cars, motorcycles, trucks

// 1. Listar marcas
$brands = orchestrator()->getFipeBrands('cars');
// [['code' => '059', 'name' => 'VOLKSWAGEN'], ...]

$brands = orchestrator()->getFipeBrands('motorcycles');
$brands = orchestrator()->getFipeBrands('trucks');

// 2. Listar modelos de uma marca
$models = orchestrator()->getFipeModels('cars', '059');
// [['code' => '5585', 'name' => 'AMAROK CD2.0...'], ...]

// 3. Anos disponíveis para um modelo (OBRIGATÓRIO antes do preço)
$years = orchestrator()->getFipeYears('cars', '059', '5585');
// [['code' => '2022-3', 'name' => '2022 Diesel'], ...]

// 4. Preço FIPE (use o code retornado em getFipeYears)
$price = orchestrator()->getFipePrice('cars', '059', '5585', '2022-3');

$price['data']['fipe_code'];        // Código FIPE
$price['data']['brand'];            // Marca
$price['data']['model'];            // Modelo
$price['data']['year'];             // Ano
$price['data']['fuel'];             // Combustível
$price['data']['price'];            // Preço (ex: R$ 180.000,00)
$price['data']['reference_month'];  // Mês de referência

Sufixo do ano: -1 Gasolina · -2 Álcool · -3 Diesel

Câmbio

// Cotação de qualquer par de moedas (maiúsculas ou minúsculas — normalizado automaticamente)
$result = orchestrator()->getExchange('USD', 'BRL');
$result = orchestrator()->getExchange('EUR', 'BRL');
$result = orchestrator()->getExchange('BTC', 'BRL');
$result = orchestrator()->getExchange('GBP', 'USD');

$result['data']['from'];        // USD
$result['data']['to'];          // BRL
$result['data']['bid'];         // Compra (ex: 5.45)
$result['data']['ask'];         // Venda (ex: 5.46)
$result['data']['high'];        // Máxima do dia
$result['data']['low'];         // Mínima do dia
$result['data']['variation'];   // Variação
$result['data']['pct_change'];  // Variação em %
$result['data']['updated_at'];  // Última atualização

Ações B3

// Ações individuais (símbolo normalizado automaticamente para maiúsculas)
$result = orchestrator()->getStock('PETR4');
$result = orchestrator()->getStock('VALE3');
$result = orchestrator()->getStock('petr4'); // também funciona

// Índices
$result = orchestrator()->getStock('IBOV');

$result['data']['symbol'];      // PETR4
$result['data']['name'];        // Petróleo Brasileiro S.A.
$result['data']['price'];       // Preço atual
$result['data']['change'];      // Variação em R$
$result['data']['change_pct'];  // Variação em %
$result['data']['open'];        // Abertura
$result['data']['day_high'];    // Máxima do dia
$result['data']['day_low'];     // Mínima do dia
$result['data']['volume'];      // Volume negociado
$result['data']['market_cap'];  // Capitalização de mercado

NCM (Nomenclatura Comum do Mercosul)

// Busca por código (8 dígitos — pontuação removida automaticamente)
$result = orchestrator()->getNcm('84713019');
$result = orchestrator()->getNcm('8471.30.19'); // também funciona

// Busca por descrição (termo de texto livre)
$result = orchestrator()->searchNcm('notebook');
$result = orchestrator()->searchNcm('computador portátil');

$result['data']['code'];         // 84713019
$result['data']['description'];  // Descrição completa
$result['data']['start_date'];   // Vigência início
$result['data']['end_date'];     // Vigência fim (null = vigente)
$result['data']['act_type'];     // Tipo do ato
$result['data']['act_number'];   // Número do ato
$result['data']['act_year'];     // Ano do ato

Empresa: sócios, Simples/MEI e CNAE

// Quadro de sócios e administradores (documentos mascarados pela Receita)
$r = orchestrator()->getCnpjPartners('33.000.167/0001-01');
$r['data']['total'];                    // 10
$r['data']['partners'][0]['name'];      // CLARICE COPPETTI
$r['data']['partners'][0]['document'];  // ***995240**
$r['data']['partners'][0]['role'];      // qualificação (Diretor, Sócio-Administrador...)

// Opção pelo Simples Nacional e pelo MEI
$r = orchestrator()->getCnpjSimples('33000167000101');
$r['data']['simples'];  // ['optant' => false, 'since' => null, 'until' => null]
$r['data']['mei'];      // idem

// CNAE (aceita 1921700 ou o formato do cartão CNPJ, 1921-7/00)
$r = orchestrator()->getCnae('1921-7/00');
$r['data']['formatted'];    // 1921-7/00
$r['data']['description'];  // FABRICAÇÃO DE PRODUTOS DO REFINO DE PETRÓLEO

// Busca pela descrição (sem acento) ou pelo começo do código
$r = orchestrator()->searchCnae('padaria');

Código IBGE e geolocalização

// Município do CEP com o código IBGE (o que a NF-e pede)
$r = orchestrator()->getIbgeByZipCode('13010-001');
$r['data']['code'];         // 3509502
$r['data']['name'];         // Campinas
$r['data']['state']['uf'];  // SP

// Municípios da UF; com nome, acha um (ignora acento, hífen e apóstrofo)
orchestrator()->getIbgeCities('SP');
orchestrator()->getIbgeCities('SP', "Santa Barbara d'Oeste");

// Município pelo código
orchestrator()->getIbgeCity('3509502');

// Coordenadas do CEP
$r = orchestrator()->getGeoByZipCode('01001-000');
$r['data']['latitude'];   // -23.5496714
$r['data']['longitude'];  // -46.6332637
$r['data']['precision'];  // zip_code | street | city

// Distância em linha reta entre dois CEPs
$r = orchestrator()->getDistance('13010-001', '01001-000');

Indicadores econômicos e PIX

// Último valor de Selic, CDI, IPCA, IPCA 12m, IGP-M, INPC e TR (Banco Central)
$r = orchestrator()->getIndicators();
$r['data'][0];  // ['indicator' => 'selic', 'name' => ..., 'unit' => '% a.a.', 'date' => ..., 'value' => 13.75]

// Um indicador; com período (Y-m-d, até 10 anos), a série
orchestrator()->getIndicator('ipca');
$r = orchestrator()->getIndicator('selic', '2025-01-01', '2025-12-31');
$r['data']['values'];  // [['date' => '2025-01-01', 'value' => 12.25], ...]

// PIX copia e cola: confere o CRC e extrai os dados (não diz se foi pago)
$r = orchestrator()->decodePix('00020126580014br.gov.bcb.pix0136...6304ABCD');
$r['data']['valid'];     // true
$r['data']['type'];      // static | dynamic
$r['data']['key'];       // chave PIX
$r['data']['key_type'];  // cpf | cnpj | email | phone | evp
$r['data']['amount'];    // null quando o valor é livre

Tributos por NCM (IBPT)

// NCM com 8 dígitos e a UF. Precisa do token do IBPT no servidor (503 sem ele).
$r = orchestrator()->getNcmTaxes('8517.13.00', 'SP');

Validação de e-mail e telefone

$r = orchestrator()->validateEmail('contato@gmial.com');
$r['data']['valid'];         // false
$r['data']['mx'];            // o domínio recebe e-mail?
$r['data']['disposable'];    // e-mail descartável
$r['data']['role_account'];  // contato@, vendas@...
$r['data']['suggestion'];    // contato@gmail.com

$r = orchestrator()->validatePhone('(21) 98765-4321');  // com DDD; sem DDI, lido como brasileiro
$r = orchestrator()->validatePhone('+1 202 555-0100');  // de outro país: informe o +DDI
$r['data']['valid'];     // true
$r['data']['type'];      // mobile | fixed_line ...
$r['data']['e164'];      // +5521987654321
$r['data']['national'];  // (21) 98765-4321

Catálogo da B3

// Filtros: search, sector, type, sort_by, sort_order, limit e page
$r = orchestrator()->getStocks(['search' => 'petr', 'limit' => 10]);
$r['data']['stocks'];

Frete (white label)

O cliente fala só com o orchestrator: ids próprios, preço final já com a margem e nenhum dado do provedor. O fluxo é: cotar → criar o envio → gerar o PIX → (pago) etiqueta emitida → imprimir → rastrear.

Serviços e cotação

use RiseTechApps\OrchestratorLink\Shipping\ShippingProduct;
use RiseTechApps\OrchestratorLink\Shipping\ShippingVolume;

orchestrator()->getShippingServices();
// [['id' => 1, 'name' => 'PAC', 'carrier' => 'Correios', 'requires_agency' => false], ...]

$quote = orchestrator()->buildQuote()
    ->from('01001-000')
    ->to('13010-001')
    ->addVolume(fn (ShippingVolume $v) => $v->dimensions(10, 20, 30)->weight(1.5))  // altura, largura, comprimento (cm), kg
    // ou produtos soltos: ->addProduct(fn (ShippingProduct $p) => $p->id('sku-1')->dimensions(10, 20, 30)->weight(0.5)->quantity(2))
    // (produto e volume: altura, largura, comprimento)
    ->insurance(150.00)
    ->services([1, 2])  // opcional: só estes serviços
    ->send();

Serviço com requires_agency pede a agência de postagem:

orchestrator()->getShippingAgencies(service: 3, postalCode: '01001-000', state: 'SP', city: 'São Paulo');

Criar o envio

use RiseTechApps\OrchestratorLink\Shipping\ShippingAddress;

$result = orchestrator()->buildShipment()
    ->reference('pedido-1050')          // sua referência, para achar o envio depois
    ->service(1)
    ->sender(fn (ShippingAddress $a) => $a
        ->name('Loja Aurora')->phone('(21) 99999-8888')->email('loja@example.com')
        ->companyDocument('14.779.686/0001-95')   // CNPJ alfanumérico também: '12.ABC.345/01DE-35'
        ->street('Rua das Flores', '42', 'Loja 3')->district('Centro')
        ->city('Rio de Janeiro', 'RJ')->postalCode('20040-020'))
    // ou um remetente salvo: ->senderId(1)
    ->recipient(fn (ShippingAddress $a) => $a
        ->name('Maria Souza')->phone('(19) 98888-7777')->email('maria@example.com')
        ->document('529.982.247-25')
        ->street('Av. Dr. Moraes Salles', '100')->district('Centro')
        ->city('Campinas', 'SP')->postalCode('13010-001'))
    ->addVolume(fn (ShippingVolume $v) => $v
        ->dimensions(10, 20, 30)->weight(1.5)
        // Correios: um objeto por volume, cada um com os próprios produtos
        ->addProduct(fn (ShippingProduct $p) => $p->name('Caneca')->quantity(2)->price(30.00)))
    // em outras transportadoras, os produtos podem ir no envio: ->addProduct(...)
    ->insurance(60.00)
    // ->invoice('3525...0019')         // NF-e (44 dígitos): dispensa a declaração de conteúdo
    // ->notifications(sender: true, recipient: false)
    // ->labelLogo($base64Png)          // logo do remetente na etiqueta
    ->idempotencyKey('pedido-1050')     // repetir com a mesma chave não cria outro envio
    ->save()                            // grava a cópia local em orchestrator_shipments
    ->create();

$shipmentId = $result['data']['id'];    // UUID do envio
$result['data']['price'];               // preço final
$result['data']['tracking_url'];        // página pública de rastreio para o destinatário

Pagamento (PIX)

A etiqueta só é comprada depois que o PIX é pago.

$pix = orchestrator()->purchaseShipment($shipmentId);
$pix['data']['pix']['code'];       // copia e cola
$pix['data']['pix']['qr_base64'];  // QR Code
$pix['data']['expires_at'];

orchestrator()->getShipmentPayment($shipmentId);  // confere no gateway

// Vários envios num PIX só (até 50)
$group = orchestrator()->payShipments([$id1, $id2]);
orchestrator()->getShipmentPaymentGroup($group['data']['id']);

// Com a chave de teste: aprova o PIX simulado e segue o fluxo no sandbox
orchestrator()->simulateShipmentPayment($shipmentId);

Etiqueta, rastreio, cancelamento e devolução

// PDF (bytes em data.content)
$label = orchestrator()->getShipmentLabel($shipmentId);
if ($label['success']) {
    return response($label['data']['content'], 200, ['Content-Type' => 'application/pdf']);
}

orchestrator()->getShipmentLabels([$id1, $id2]);  // um PDF com várias

orchestrator()->trackShipment($shipmentId);       // sincroniza status e rastreio
orchestrator()->getShipment($shipmentId);         // envio com o histórico
orchestrator()->listShipments(['status' => 'posted', 'external_reference' => 'pedido-1050', 'per_page' => 20]);
orchestrator()->listShipments(['label_code' => 'ORD-123']);  // pelo código impresso na etiqueta

orchestrator()->cancelShipment($shipmentId, 'Cliente desistiu');  // se pago, o PIX é estornado

// Devolução: endereços do original invertidos
orchestrator()->reverseShipment($shipmentId, [
    'service' => 1,
    'volumes' => [['height' => 10, 'width' => 20, 'length' => 30, 'weight' => 1.5]],
]);

Status do envio: pending, awaiting_payment, processing, purchased, label_ready, posted, delivered, undelivered e cancelled.

Remetentes salvos

orchestrator()->getShippingSenders();
orchestrator()->createShippingSender([
    'from'       => ShippingAddress::make()->name('Loja')->/* ... */toArray(),
    'label'      => 'Loja Centro',
    'is_default' => true,
]);
// O endereço solto, junto do label, também funciona: o client o agrupa em `from`.
orchestrator()->updateShippingSender(1, ['from' => [...], 'label' => 'Loja Centro']);
orchestrator()->deleteShippingSender(1);

Webhook

O orchestrator avisa cada mudança de status (shipment.payment_confirmed, shipment.purchased, shipment.label_ready, shipment.posted, shipment.delivered, shipment.undelivered, shipment.cancelled) numa URL HTTPS pública.

$r = orchestrator()->setShippingWebhook('https://minhaloja.com.br/webhooks/frete');
$secret = $r['data']['secret'];  // mostrado só agora: guarde (ex.: no .env)

Na rota que recebe:

use RiseTechApps\OrchestratorLink\Models\Shipment;
use RiseTechApps\OrchestratorLink\Shipping\ShippingWebhook;

Route::post('/webhooks/frete', function (Request $request) {
    if (!ShippingWebhook::verifyRequest($request, config('services.orchestrator.webhook_secret'))) {
        abort(401);
    }

    // X-Orchestrator-Delivery identifica a entrega: use para não processar duas vezes.
    Shipment::syncFromOrchestrator($request->input('data'));

    return response()->noContent();
});

Resposta fora de 2xx é reenviada até 8 vezes ao longo de ~1 dia. Avisos com mais de 5 minutos são recusados por padrão (verify(..., tolerance: 300)).

Model Shipment

->save() no builder e Shipment::syncFromOrchestrator($data) gravam a cópia local em orchestrator_shipments, pelo orchestrator_id. Um aviso parcial não apaga o que já estava salvo.

use RiseTechApps\OrchestratorLink\Models\Shipment;

$shipment = Shipment::where('orchestrator_id', $shipmentId)->first();
Shipment::where('external_reference', 'pedido-1050')->first();
Shipment::pending()->get();  // também posted() e delivered()

$shipment->isAwaitingPayment();
$shipment->isProcessing();   // pago, comprando a etiqueta
$shipment->isPurchased();
$shipment->isLabelReady();
$shipment->isPosted();
$shipment->isDelivered();
$shipment->isCancelled();

// Colunas: orchestrator_id, external_reference, service_id, service_name, carrier,
// status, sandbox, tracking_code, tracking_url, from_postal_code, from_data (json),
// to_postal_code, to_data (json), products (json), volumes (json), options (json),
// price, paid_at, posted_at, delivered_at, cancelled_at.

Referência de Métodos

Método Descrição
getCPF($cpf, $date?) Consulta CPF
getCNPJ($cnpj) Consulta CNPJ
getZipCode($cep) Consulta CEP
getBanks() Lista bancos
getCountries() Lista países
getCountryInfo($country) Info de um país (nome, ISO2 ou ISO3)
getStates($country) Estados de um país
getStateInfo($country, $state) Info de um estado
getCities($country, $state) Cidades de um estado
getHolidays($state, $year) Feriados estaduais e nacionais
getWeather($city, $country, $state?) Previsão do tempo
getDomain($domain) WHOIS de domínio
getCalendar($country, $state, $city, $start, $end) Calendário (feriados + clima)
getFipeBrands($type) Marcas FIPE (cars/motorcycles/trucks)
getFipeModels($type, $brand) Modelos FIPE de uma marca
getFipeYears($type, $brand, $model) Anos disponíveis para um modelo
getFipePrice($type, $brand, $model, $year) Preço FIPE
getExchange($from, $to) Cotação de câmbio
getStock($symbol) Cotação de ação B3 ou índice
getNcm($code) NCM por código (8 dígitos)
searchNcm($term) NCM por descrição
getStocks($filters?) Catálogo de ativos da B3
getCnpjPartners($cnpj) Sócios do CNPJ (QSA)
getCnpjSimples($cnpj) Simples Nacional e MEI
getCnae($code) CNAE por código
searchCnae($term) Busca CNAE
getIbgeCities($uf, $name?) Municípios da UF com código IBGE
getIbgeCity($code) Município pelo código IBGE
getIbgeByZipCode($cep) Código IBGE do CEP
getGeoByZipCode($cep) Coordenadas do CEP
getDistance($from, $to) Distância entre CEPs
getIndicators() Indicadores econômicos (último valor)
getIndicator($indicator, $from?, $to?) Um indicador ou a série
decodePix($code) Lê PIX copia e cola
getNcmTaxes($code, $uf) Tributos do NCM (IBPT)
validateEmail($email) Validação de e-mail
validatePhone($phone) Validação de telefone
getShippingServices() Serviços de entrega
buildQuote() / quoteShipping($data) Cotação
getShippingAgencies($service, $postalCode, $state, $city, $district?) Agências de postagem
getShippingSenders() / createShippingSender($data) / updateShippingSender($id, $data) / deleteShippingSender($id) Remetentes salvos
buildShipment() / createShipment($data, $idempotencyKey?) Cria envio
listShipments($filters?) Lista envios
getShipment($id) Envio com histórico
purchaseShipment($id, $idempotencyKey?) Gera o PIX
getShipmentPayment($id) Pagamento do envio
payShipments($ids, $idempotencyKey?) / getShipmentPaymentGroup($group) PIX de vários envios
simulateShipmentPayment($id) Simula pagamento (chave de teste)
cancelShipment($id, $reason?) Cancela (estorna se pago)
reverseShipment($id, $data, $idempotencyKey?) Devolução
trackShipment($id) Sincroniza rastreio
getShipmentLabel($id) / getShipmentLabels($ids) Etiqueta em PDF
getShippingWebhook() / setShippingWebhook($url) / deleteShippingWebhook() Webhook da conta

Requisitos

  • PHP >= 8.4
  • Laravel >= 12

💡 Desenvolvido por Rise Tech