elgibor-solution / laravel-delivery-gosend
Integrasi dengan API GoSend untuk pengiriman barang
Installs: 8
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
pkg:composer/elgibor-solution/laravel-delivery-gosend
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7|^8
- illuminate/database: ^10|^11|^12
- illuminate/events: ^10|^11|^12
- illuminate/http: ^10|^11|^12
- illuminate/support: ^10|^11|^12
Requires (Dev)
- orchestra/testbench: ^8.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
README
Integration package for GoSend delivery API (Instant & Same Day) for Laravel 10+, designed to support multi-tenant usage via runtime config injection.
Note: This library is not an official GoSend SDK. It is a community package built around the integration guide.
Features
- Create GoSend bookings (Instant / Same Day / InstantCar).
- Retrieve booking status (by
orderNoorstoreOrderId). - Cancel bookings.
- Price & distance estimation.
- Webhook endpoint to receive driver / booking status updates.
GoSendDeliverymodel to store bookings.- Event
GoSendStatusUpdateddispatched on every webhook update. - Facade
GoSendfor quick usage. - Config-driven & extendable architecture.
- Multi-tenant ready by overriding config at runtime (
withConfig()).
Requirements
- PHP
^8.2 - Laravel
^10.0 - ext-json
guzzlehttp/guzzle^7.0|^8.0
Installation
composer require elgibor-solution/laravel-delivery-gosend
The service provider and facade will be auto-discovered.
Publish Config & Migrations
php artisan vendor:publish --provider="ESolution\GoSend\Providers\GoSendServiceProvider" --tag=gosend-config php artisan vendor:publish --provider="ESolution\GoSend\Providers\GoSendServiceProvider" --tag=gosend-migrations
Run migrations:
php artisan migrate
Configuration
Main config file: config/gosend.php.
Environment & Base URLs
'environment' => env('GOSEND_ENV', 'staging'), 'base_urls' => [ 'staging' => env('GOSEND_STAGING_URL', 'https://integration-kilat-api.gojekapi.com'), 'production' => env('GOSEND_PRODUCTION_URL', 'https://kilat-api.gojekapi.com'), ],
Set in .env:
GOSEND_ENV=staging GOSEND_STAGING_CLIENT_ID=your-staging-client-id GOSEND_STAGING_PASS_KEY=your-staging-pass-key GOSEND_PRODUCTION_CLIENT_ID=your-prod-client-id GOSEND_PRODUCTION_PASS_KEY=your-prod-pass-key
HTTP Options
'http' => [ 'timeout' => env('GOSEND_HTTP_TIMEOUT', 10), 'retries' => env('GOSEND_HTTP_RETRIES', 2), 'retry_sleep_ms' => env('GOSEND_HTTP_RETRY_SLEEP_MS', 250), ],
Routes & Webhook
'routes' => [ 'enabled' => env('GOSEND_ROUTES_ENABLED', true), 'prefix' => env('GOSEND_ROUTE_PREFIX', 'gosend'), 'middleware' => ['api'], ], 'webhook' => [ 'token_header' => env('GOSEND_WEBHOOK_TOKEN_HEADER', 'X-Callback-Token'), 'token' => env('GOSEND_WEBHOOK_TOKEN'), 'route_name' => 'gosend.webhook', ],
In .env:
GOSEND_WEBHOOK_TOKEN=some-random-secret
You must register this token & webhook URL with GoSend.
Multi-tenant Usage (Runtime Config)
The package is config-driven, but also allows runtime overrides via withConfig() on the client or facade.
Typical pattern:
- Store GoSend configuration (environment, client ID, pass key, etc.) per tenant in your database.
- When handling a request for a specific tenant, load that row.
- Call
withConfig()and then use the client as usual.
Example:
use GoSend; use ESolution\GoSend\Contracts\GoSendClientInterface; // Load from DB (pseudo code) $tenantConfig = [ 'environment' => $store->gosend_environment, // "staging" or "production" 'credentials' => [ $store->gosend_environment => [ 'client_id' => $store->gosend_client_id, 'pass_key' => $store->gosend_pass_key, ], ], ]; // Either via facade: $client = GoSend::withConfig($tenantConfig); // Or via dependency injection: $baseClient = app(GoSendClientInterface::class); $client = $baseClient->withConfig($tenantConfig); // Now use $client for this tenant.
Usage
1. Creating a Booking
Using Facade:
use GoSend; $payload = [ 'paymentType' => 3, 'shipment_method' => 'Instant', 'routes' => [[ 'originName' => 'Pak Andri', 'originNote' => 'Tunggu di lobby', 'originContactName' => 'The Kingdom Shop', 'originContactPhone' => '6285201311802', 'originLatLong' => '-6.1263348,106.7890888', 'originAddress' => 'Alamat lengkap asal', 'destinationName' => 'Pak Nando', 'destinationNote' => 'Tolong hati-hati', 'destinationContactName' => 'Toko Jaya Agung', 'destinationContactPhone'=> '6281254564161', 'destinationLatLong' => '-6.284508001748839,106.8295789', 'destinationAddress' => 'Alamat lengkap tujuan', 'item' => 'Sepatu, Sendal, Kaos Kaki', 'storeOrderId' => 'AWB-123456', 'insuranceDetails' => [ 'applied' => 'false', 'fee' => '0', 'product_description' => 'Sepatu, Sendal, Kaos Kaki', 'product_price' => '500.000', ], ]], ]; $delivery = GoSend::createBooking($payload); // $delivery is ESolution\GoSend\Models\GoSendDelivery
Using dependency injection with multi-tenant config:
use ESolution\GoSend\Contracts\GoSendClientInterface; public function createForTenant(GoSendClientInterface $baseClient) { $store = // ... load store/tenant model $client = $baseClient->withConfig([ 'environment' => $store->gosend_environment, 'credentials' => [ $store->gosend_environment => [ 'client_id' => $store->gosend_client_id, 'pass_key' => $store->gosend_pass_key, ], ], ]); $delivery = $client->createBooking($payload); }
2. Get Status
$status = GoSend::getStatusByOrderNo('GK-11-170563'); $delivery = \ESolution\GoSend\Models\GoSendDelivery::where('order_no', 'GK-11-170563')->first();
Or by storeOrderId:
$status = GoSend::getStatusByStoreOrderId('AWB-123456');
3. Cancel Booking
GoSend::cancelBooking('GK-11-170563');
4. Estimate Price
$estimate = GoSend::estimatePrice( originLatLong: '-6.1263348,106.7890888', destinationLatLong: '-6.284508001748839,106.8295789', paymentType: 3 ); // $estimate['Instant']['price']['total_price'] ...
5. Webhook Flow (End-to-End)
- Expose webhook URL (e.g.
https://your-app.com/gosend/webhook). - Register this URL & token with GoSend.
- When booking status changes, GoSend will call this endpoint with a payload like:
{
"@type": "booking_event",
"entity_id": "GK-11-117385",
"type": "DRIVER_NOT_FOUND",
"event_date": 1648542933000,
"event_id": "7444acc4-0f14-419d-806c-6e245607c274",
"partner_id": "601",
"destination_type": "market_place",
"booking_id": "GK-11-117385",
"status": "no_driver",
"booking_status": "no_driver",
"booking_type": "instant",
"driver_name": "",
"driver_phone": "",
"total_distance_in_kms": 1.184000015258789,
"price": 20000.0,
"receiver_name": "",
"live_tracking_url": "http://..."
}
ProcessWebhookjob updates theGoSendDeliveryrecord.- Event
GoSendStatusUpdatedis dispatched.
Example listener in your app:
namespace App\Listeners; use ESolution\GoSend\Events\GoSendStatusUpdated; use Illuminate\Support\Facades\Log; class LogGoSendStatus { public function handle(GoSendStatusUpdated $event): void { Log::info('GoSend status updated', [ 'order_no' => $event->delivery->order_no, 'status' => $event->delivery->status, 'event' => $event->payload['type'] ?? null, ]); } }
Register in EventServiceProvider:
protected $listen = [ \ESolution\GoSend\Events\GoSendStatusUpdated::class => [ \App\Listeners\LogGoSendStatus::class, ], ];
Example Integration: Controller & Job
Controller
namespace App\Http\Controllers; use ESolution\GoSend\Contracts\GoSendClientInterface; use Illuminate\Http\Request; class OrderDeliveryController extends Controller { public function createForOrder(Request $request, GoSendClientInterface $baseClient) { $order = /* find your order */; $store = $order->store; // example relation $client = $baseClient->withConfig([ 'environment' => $store->gosend_environment, 'credentials' => [ $store->gosend_environment => [ 'client_id' => $store->gosend_client_id, 'pass_key' => $store->gosend_pass_key, ], ], ]); $payload = [ 'paymentType' => 3, 'shipment_method' => 'Instant', 'routes' => [[ 'originName' => $order->seller_name, 'originContactName' => $order->seller_contact_name, 'originContactPhone' => $order->seller_phone, 'originLatLong' => $order->seller_latlong, 'originAddress' => $order->seller_address, 'destinationName' => $order->buyer_name, 'destinationContactName' => $order->buyer_contact_name, 'destinationContactPhone'=> $order->buyer_phone, 'destinationLatLong' => $order->buyer_latlong, 'destinationAddress' => $order->buyer_address, 'item' => $order->item_summary, 'storeOrderId' => $order->awb_code, ]], ]; $delivery = $client->createBooking($payload); $order->gosend_delivery_id = $delivery->id; $order->save(); return response()->json([ 'message' => 'GoSend delivery created', 'order_no' => $delivery->order_no, ]); } }
Job: Refresh Status
namespace App\Jobs; use ESolution\GoSend\Contracts\GoSendClientInterface; use ESolution\GoSend\Models\GoSendDelivery; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class RefreshGoSendStatus implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public GoSendDelivery $delivery; public function __construct(GoSendDelivery $delivery) { $this->delivery = $delivery; } public function handle(GoSendClientInterface $client): void { if (! $this->delivery->order_no) { return; } $client->getStatusByOrderNo($this->delivery->order_no); } }
Testing
Install dev dependencies and run tests:
composer install
composer test
This will run the provided Pest tests using orchestra/testbench.
Changelog
All notable changes to this project will be documented here.
v0.1.0– Initial release (GoSend booking, status, cancel, estimate, webhook, event, runtime multi-tenant config support).
License
This package is open-sourced software licensed under the Apache-2.0 license.
Sponsor / Donation (Optional)
If this package saves you development time, you can support the maintainer:
- {{your-donation-link-here}}
Thank you! 🙏