Integrates Revolut Merchant API for payment processing in Laravel. Activates when setting up payments, configuring Revolut, creating orders, handling webhooks, processing refunds, or when user mentions Revolut, payment gateway, merchant API, checkout, or online payments.
How this skill is triggered — by the user, by Claude, or both
Slash command
/laravel-revolut-skill:revolut-integrationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Activate this skill when:
Activate this skill when:
Revolut Merchant API: https://developer.revolut.com/docs/merchant-api/
Install via Composer:
composer require revolut/laravel-integration
Auto-discovery registers RevolutServiceProvider and the Revolut facade automatically.
Publish configuration:
php artisan vendor:publish --tag=revolut-config
Run migrations:
php artisan migrate
This creates revolut_customers and revolut_orders tables.
Add to .env:
REVOLUT_API_KEY=sk_sandbox_your_key_here
REVOLUT_ENVIRONMENT=sandbox # or "production"
REVOLUT_WEBHOOK_SECRET=your_secret
REVOLUT_WEBHOOK_ROUTE=revolut/webhook
Important: Use sandbox credentials during development. Never commit API keys to version control.
config/revolut.php)| Key | Default | Description |
|---|---|---|
api_key | '' | Your Revolut Merchant API key |
environment | sandbox | sandbox or production |
webhook_secret | '' | HMAC signing secret from Revolut dashboard |
webhook_route | revolut/webhook | URI for receiving webhooks |
timeout | 30 | HTTP request timeout in seconds |
The second argument to RevolutCheckout(public_id, env) must match your Revolut environment:
.env value | SDK string |
|---|---|
sandbox | 'sandbox' |
production | 'prod' |
Pass it dynamically from PHP to avoid hardcoding:
{{-- In a Blade view --}}
<script>
const revolutEnv = '{{ config('revolut.environment') === 'production' ? 'prod' : 'sandbox' }}';
RevolutCheckout(publicId, revolutEnv)...
</script>
Or return it from your backend endpoint:
return response()->json([
'public_id' => $order->public_id,
'env' => config('revolut.environment') === 'production' ? 'prod' : 'sandbox',
]);
The Revolut Merchant Web SDK supports 7 frontend integration methods. Choose based on your UX requirements:
| Integration | Best for | Skill |
|---|---|---|
| Revolut Checkout | Popup card form over your page | revolut-checkout |
| Revolut Pay | One-click button for Revolut account holders | revolut-pay |
| Apple Pay & Google Pay | Wallet buttons on supported devices | revolut-apple-google-pay |
| Pay by Bank | Open banking / account-to-account | revolut-pay-by-bank |
| Card Field | Inline card form with full style control | revolut-card-field |
| Card Popup | Revolut-hosted modal overlay | revolut-card-popup |
| Promotional Widgets | Buy now banners and payment badges | revolut-promotional-widgets |
All SDK methods require a public_id (available as $order->public_id after Revolut::createOrder()).
Load the SDK via <script src="https://merchant.revolut.com/embed.js"></script> (or upsell/bundle.js for widgets).
See individual skills for implementation details.
use Lartisan\Revolut\Facades\Revolut;
$order = Revolut::createOrder([
'amount' => 1000, // Amount in smallest unit (1000 = £10.00)
'currency' => 'GBP',
'description' => 'Order #123',
'redirect_url' => route('payment.success'),
'cancel_redirect_url' => route('payment.cancel'), // Must use cancel_redirect_url, not cancel_url
]);
// Redirect user to hosted checkout page
return redirect()->away($order->checkout_url);
$order = Revolut::getOrder('order_abc123');
if ($order->isCompleted()) {
// Payment confirmed — fulfill order
}
Helper methods: isCompleted(), isPending(), isAuthorised(), isCancelled().
Order states flow: PENDING → PROCESSING → AUTHORISED → COMPLETED
// Create order with manual capture
$order = Revolut::createOrder([
'amount' => 5000,
'currency' => 'GBP',
'capture_mode' => 'manual',
]);
// Capture when ready (e.g. on shipment)
Revolut::captureOrder($order->revolut_order_id);
// Partial capture
Revolut::captureOrder($order->revolut_order_id, ['amount' => 3000]);
// Full refund
Revolut::refundOrder('order_abc123');
// Partial refund
Revolut::refundOrder('order_abc123', [
'amount' => 500,
'description' => 'Customer request',
]);
// Create customer
$customer = Revolut::createCustomer([
'email' => '[email protected]',
'full_name' => 'Jane Smith',
'phone' => '+447911123456',
]);
// Link to an order
$order = Revolut::createOrder([
'amount' => 2000,
'currency' => 'GBP',
'customer_id' => $customer->revolut_customer_id,
]);
The package registers the webhook route automatically. Configure the URL in the Revolut Business dashboard:
https://yourdomain.com/revolut/webhook
Copy the signing secret → set REVOLUT_WEBHOOK_SECRET in .env.
use Lartisan\Revolut\Events\OrderCompleted;
Event::listen(OrderCompleted::class, function (OrderCompleted $event) {
$orderId = $event->getOrderId();
// Fulfill the order…
});
Available events: OrderCompleted, OrderAuthorised, OrderCancelled, OrderPaymentFailed.
All webhooks are automatically validated via HMAC-SHA256. Invalid signatures are rejected with 403.
The Revolut-Signature header uses a v1= prefix (e.g. v1=<hmac_sha256>). The package handles this automatically.
Revolut::createOrder(array $params): RevolutOrder
Revolut::getOrder(string $orderId): RevolutOrder
Revolut::captureOrder(string $orderId, array $params = []): RevolutOrder
Revolut::cancelOrder(string $orderId): RevolutOrder
Revolut::refundOrder(string $orderId, array $params = []): array
Revolut::listOrders(array $filters = []): array
Revolut::createCustomer(array $params): RevolutCustomer
Revolut::getCustomer(string $customerId): RevolutCustomer
Revolut::updateCustomer(string $customerId, array $params): RevolutCustomer
Revolut::deleteCustomer(string $customerId): bool
Revolut::listCustomers(array $filters = []): array
RevolutOrder| Property | Type | Description |
|---|---|---|
revolut_order_id | string | Revolut's internal order ID (used for API calls) |
public_id | string | Public token passed to the frontend SDK (RevolutCheckout(public_id, ...)) |
state | string | PENDING, AUTHORISED, COMPLETED, CANCELLED, FAILED |
amount | int | Amount in smallest currency unit |
currency | string | ISO 4217 currency code |
checkout_url | string|null | Hosted checkout URL (for redirect-based flows) |
formatted_amount | string | Accessor: e.g. "10.00 GBP" |
RevolutCustomer| Property | Type | Description |
|---|---|---|
revolut_customer_id | string | Revolut's customer ID |
email | string|null | Customer email |
full_name | string|null | Customer name |
All API methods throw Lartisan\Revolut\Exceptions\RevolutException on failure:
use Lartisan\Revolut\Exceptions\RevolutException;
try {
$order = Revolut::createOrder([...]);
} catch (RevolutException $e) {
$e->getMessage(); // Human-readable error
$e->getStatusCode(); // HTTP status code (404, 422, etc.)
$e->getErrors(); // Validation errors array
$e->isUnauthorized(); // true if 401
$e->isNotFound(); // true if 404
$e->isRateLimited(); // true if 429
}
If using Claude Desktop or Claude Code, configure MCP for live testing:
{
"mcpServers": {
"revolut": {
"command": "php",
"args": ["vendor/revolut/laravel-integration/mcp/bin/revolut-mcp-server"],
"env": {
"REVOLUT_API_KEY": "sk_sandbox_xxxxx",
"REVOLUT_ENVIRONMENT": "sandbox"
}
}
}
}
1000 (pence), not 10customer_email instead of email in createOrder() (silently wrong field name)cancel_url instead of cancel_redirect_url (silently ignored by the API).env committed to Gitorder_id for reconciliationcheckout_url — create a fresh order each timengrok for local testing| Issue | Solution |
|---|---|
| "Invalid API key" (401) | Check REVOLUT_API_KEY in .env matches correct environment |
| Webhook signature fails | Verify REVOLUT_WEBHOOK_SECRET matches Revolut dashboard |
| HTTP 422 on order creation | Call $e->getErrors() — check currency code and amount |
| Orders not in database | Run php artisan migrate |
| Checkout URL not working | Don't reuse URLs — checkout_url expires |
| Webhook not received | Check URL in Revolut dashboard; must be HTTPS in production |
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub lartisan/laravel-revolut-skill --plugin laravel-revolut-skill