Developer docs Core 2.2 · Pro 1.x

Search documentation

Search Core and Pro guides, including code examples.

PRO · COMMERCIAL

Review invitations.

Install the complete review experience, choose an interface, and configure customer and team workflows.

← All Pro topics

Invitations

Invite existing customer accounts without bypassing approval or granting a verified badge:

php artisan vendor:publish --tag=review-rateable-pro-invitations-migrations
php artisan migrate
'invitations' => [
    'enabled' => true,
    'route' => 'reviews.invitation',
    'ability' => null,
    'expires_in_days' => 14,
    'changes_per_minute' => 10,
    'email_enabled' => true,
    'mailer' => null,
    'queue' => null,
],

Issuers must pass moderation and view permissions. An optional invitation ability receives the target and recipient for contact/eligibility rules. Recipients must be saved users with a valid email and compatible numeric identity on the target's connection.

Pro does not register a route. Add your own authenticated, signed endpoint with an {invitation} parameter, scoped correctly for your application:

use Codebyray\ReviewRateablePro\Models\ReviewInvitation;
use Codebyray\ReviewRateablePro\Services\ReviewInvitationManager;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/reviews/invitations/{invitation}', function (
    Request $request,
    ReviewInvitation $invitation,
    ReviewInvitationManager $invitations
) {
    $data = $request->validate([
        'token' => ['required', 'string', 'size:64'],
    ]);
    $invitation = $invitations->open($invitation, $data['token']);

    return response()->view('reviews.invitation', [
        'invitation' => $invitation,
        'reviewable' => $invitation->reviewable,
    ])->header('Cache-Control', 'private, no-store')
        ->header('Referrer-Policy', 'no-referrer')
        ->header('X-Robots-Tag', 'noindex, nofollow');
})->middleware(['auth', 'signed'])->name('reviews.invitation');

Use auth:your-guard for a non-default Pro guard. Multi-tenant applications must bind invitations on the correct tenant connection and apply their own target scope.

Render the form in reviews.invitation inside your normal layout:

<livewire:review-rateable-pro-review-form
    :reviewable="$reviewable"
    :department="$invitation->department"
    :invitation-id="$invitation->id" />

From an authorized private workflow:

$invitations = app(ReviewInvitationManager::class);
$issued = $invitations->issue(
    $product, $customer, $product->name, sendEmail: true
);

// $issued->url is returned only for a newly issued link.
$renewed = $invitations->renew($issued->invitation, sendEmail: true);

The signed link is not authentication; the invited account must sign in. Opening and submitting recheck recipient, token, expiry, and permissions. Renewal invalidates old links and open forms.

There is one lifetime invitation per target/department/customer. Duplicate issuance returns the existing record with a null URL and sends no new email. Only a token hash is saved; renew explicitly if you need another link. Existing reviews, including pending/hidden ones, prevent new invitations.

Statuses are pending, opened, expired, and reviewed. Opened means an authenticated page visit, not email tracking. Reviewed means submitted, not approved. Normal Pro submissions complete matching invitations; custom core writers should call recordReview($review) in the author-authenticated creation workflow.

Email additionally requires sendEmail: true on issue/renew. An encrypted job dispatches after commit; configure a real mail transport and asynchronous queue worker in production:

php artisan queue:work

The demo uses an array mailer and does not deliver external emails. Mail acceptance is not proof of receipt, and worker retries can produce duplicates. Monitor failed jobs. Protect signed URLs from logs, referrers, public APIs, and shared caches; only contact customers you are permitted to email.