payted/payted-php

Official PHP SDK for Payted Payment Gateway - M-Pesa, Emola & Visa payments in Mozambique

Maintainers

Package info

github.com/anselmocossa/payted-php

Homepage

pkg:composer/payted/payted-php

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-02-02 06:49 UTC

This package is auto-updated.

Last update: 2026-03-02 07:01:32 UTC


README

SDK oficial PHP para integração com o gateway de pagamentos Payted - M-Pesa, Emola e Visa em Moçambique.

Instalação

composer require payted/payted-php

Configuração

Uso Directo

use Payted\Payted;

$client = Payted::client('seu-api-token', [
    'base_url' => 'https://pay.ted.co.mz/api', // opcional
    'timeout' => 60, // opcional, em segundos
]);

Laravel

O SDK inclui auto-discovery para Laravel. Após instalar, publique a configuração:

php artisan vendor:publish --tag=payted-config

Configure no seu .env:

PAYTED_API_TOKEN=seu-api-token
PAYTED_WEBHOOK_SECRET=seu-webhook-secret
PAYTED_APP_ID=1

Uso

Checkout (Redirect)

Para pagamentos onde o cliente é redirecionado para uma página de checkout:

use Payted\Payted;

$client = Payted::client('seu-api-token');

$checkout = $client->checkout()->create([
    'app_id' => 1,
    'valor_total' => 500.00,
    'referencia_externa' => 'PEDIDO-123',
    'itens' => [
        [
            'nome' => 'Curso de PHP',
            'quantidade' => 1,
            'preco_unitario' => 500.00,
        ],
    ],
    'return_url' => 'https://meusite.com/sucesso',
    'cancel_url' => 'https://meusite.com/cancelado',
]);

// Redirecionar o cliente
header('Location: ' . $checkout->checkoutUrl);
exit;

Débito Directo (Síncrono)

Para pagamentos sem redirect (ex: POS, subscrições):

$debit = $client->debit()->process([
    'app_id' => 1,
    'valor_total' => 100.00,
    'referencia_externa' => 'POS-456',
    'metodo' => 'mpesa', // ou 'emola'
    'numero_cliente' => '841234567',
]);

if ($debit->isPaid()) {
    echo "Pagamento confirmado! ID: " . $debit->transacaoId;
} else {
    echo "Pagamento falhou: " . $debit->erro;
}

Consultar Status

// Por ID do pagamento
$status = $client->debit()->status('TED12345678');

// Por referência externa
$status = $client->debit()->statusByReference('PEDIDO-123');

if ($status->isPaid) {
    echo "Pagamento confirmado!";
} elseif ($status->isPending()) {
    echo "Aguardando confirmação...";
} else {
    echo "Pagamento falhou.";
}

Webhooks

Valide webhooks recebidos do Payted:

use Payted\Webhook\WebhookValidator;

$validator = new WebhookValidator('seu-webhook-secret');

try {
    $event = $validator->constructEvent(
        file_get_contents('php://input'),
        $_SERVER['HTTP_X_PAYTED_SIGNATURE']
    );

    if ($event->isPaymentCompleted()) {
        $referenciaExterna = $event->getReferenciaExterna();
        $pagamentoId = $event->getPagamentoId();

        // Processar pagamento confirmado
        // Actualizar pedido no banco de dados
    }

    if ($event->isPaymentFailed()) {
        // Processar falha de pagamento
    }

    http_response_code(200);
    echo json_encode(['received' => true]);

} catch (\Payted\Exceptions\WebhookException $e) {
    http_response_code(400);
    echo json_encode(['error' => $e->getMessage()]);
}

Laravel

Usando a Facade

use Payted\Laravel\PaytedFacade as Payted;

// Checkout
$checkout = Payted::checkout()->create([
    'app_id' => config('payted.app_id'),
    'valor_total' => 500.00,
    'referencia_externa' => 'PEDIDO-123',
]);

return redirect($checkout->checkoutUrl);

Injeção de Dependência

use Payted\PaytedClient;

class PaymentController extends Controller
{
    public function __construct(
        private PaytedClient $payted
    ) {}

    public function checkout(Request $request)
    {
        $checkout = $this->payted->checkout()->create([
            'app_id' => config('payted.app_id'),
            'valor_total' => $request->total,
            'referencia_externa' => $request->order_id,
        ]);

        return redirect($checkout->checkoutUrl);
    }
}

Webhook Controller

use Illuminate\Http\Request;
use Payted\Webhook\WebhookValidator;
use Payted\Exceptions\WebhookException;

class WebhookController extends Controller
{
    public function __construct(
        private WebhookValidator $validator
    ) {}

    public function handle(Request $request)
    {
        try {
            $event = $this->validator->constructEvent(
                $request->getContent(),
                $request->header('X-Payted-Signature')
            );

            if ($event->isPaymentCompleted()) {
                // Marcar pedido como pago
                Order::where('reference', $event->getReferenciaExterna())
                    ->update(['status' => 'paid']);
            }

            return response()->json(['received' => true]);

        } catch (WebhookException $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}

Transações C2B (com Parceiro)

Para pagamentos com divisão entre a aplicação e um parceiro:

$checkout = $client->checkout()->create([
    'app_id' => 1,
    'valor_total' => 1000.00,
    'referencia_externa' => 'VENDA-789',

    // Dados do parceiro
    'parceiro_nome' => 'Loja do João',
    'parceiro_email' => 'joao@loja.com',
    'parceiro_contacto' => '841234567',
    'parceiro_tipo' => 'comerciante',

    // Divisão de receita
    'percentagem_app' => 10,      // 10% para a plataforma
    'percentagem_parceiro' => 90, // 90% para o parceiro
]);

echo "Tipo: " . $checkout->tipoTransacao; // C2B
echo "Parceiro ID: " . $checkout->parceiroId;

Tratamento de Erros

use Payted\Exceptions\AuthenticationException;
use Payted\Exceptions\ValidationException;
use Payted\Exceptions\RateLimitException;
use Payted\Exceptions\ApiException;

try {
    $debit = $client->debit()->process([...]);
} catch (AuthenticationException $e) {
    // Token inválido (401)
    echo "Erro de autenticação: " . $e->getMessage();
} catch (ValidationException $e) {
    // Dados inválidos (422)
    echo "Erros de validação:";
    foreach ($e->getErrors() as $field => $errors) {
        echo "$field: " . implode(', ', $errors);
    }
} catch (RateLimitException $e) {
    // Limite excedido (429)
    echo "Limite excedido. Tente novamente em " . $e->getRetryAfter() . " segundos.";
} catch (ApiException $e) {
    // Erro do servidor
    echo "Erro da API: " . $e->getMessage();
}

Métodos de Pagamento

Método Código Descrição
M-Pesa mpesa Pagamento via M-Pesa
Emola emola Pagamento via Emola
Visa visa Pagamento via cartão Visa (apenas checkout)

Requisitos

  • PHP 8.1+
  • Guzzle HTTP 7.0+

Suporte

Licença

MIT