# Customer requests from your app to your phone

> Push every quote or contact request from your app to your iPhone with its details, one group per request, and on-device AI that drafts the reply.

Source: https://honk-me.app/guides/customer-requests-to-your-phone

A contact form usually emails you, and the email waits in an inbox full of newsletters. For a small agency or a shop, a new quote request is worth a push: who asked, what they want, the budget, and a link to answer.

This guide sends each request to Honk from a Laravel app, and points to the same recipe for Node, Go, Swift, Kotlin and Rust. Every request becomes its own group, so two customers never fold into one notification, and a retried job never notifies twice.

## Before you start

- A Honk account (invite-only for now: [request access](https://honk-me.app/request-access)) and a project, for example “Storefront”, with an ingestion key.
- Laravel 13 with the package installed: see [Laravel and PHP](https://honk-me.app/integrations/laravel#install).

## 1. A notification for the request

Create a notification that uses the `honk` channel. It’s queued, so the customer’s request stays fast, and it goes out after the database transaction commits:

```php
// app/Notifications/CustomerRequested.php
namespace App\Notifications;

use App\Models\CustomerRequest;
use HonkMe\Laravel\Notifications\HonkMessage;
use HonkMe\Laravel\Notifications\ToHonk;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\Attributes\Backoff;
use Illuminate\Queue\Attributes\Tries;
use Illuminate\Support\Str;

#[Tries(5)]
#[Backoff(10, 60, 300, 900)]
class CustomerRequested extends Notification implements ShouldQueue, ToHonk
{
    use Queueable;

    public function __construct(public CustomerRequest $request)
    {
        $this->afterCommit();
    }

    public function via(object $notifiable): array
    {
        return ['honk']; // add 'mail', 'database', … as you like
    }

    public function toHonk(object $notifiable): HonkMessage
    {
        $r = $this->request;

        return HonkMessage::create()
            ->title(Str::limit("New request: {$r->subject}", 150))
            ->line("{$r->name} ({$r->company})")
            ->line(Str::limit($r->body, 2000))       // message: ≤ 8192 bytes
            ->light()                                // a light honk (info)
            ->category('customers')
            ->groupKey("requests/{$r->id}")          // one group per request
            ->occurredAt($r->created_at)
            ->url(route('admin.requests.show', $r))  // https only, shown as "Open link"
            // buttons, up to 3 (the first is the main one): https://, mailto:, tel: or sms:
            ->action('Reply by email', "mailto:{$r->email}")
            ->action('Call', "tel:{$r->phone}")
            ->meta('request_id', (string) $r->id);
    }
}
```

The fields that matter:

- **`groupKey("requests/{$r->id}")`**: one group per request. Follow-ups about the same request, like a reminder an hour later, update that group instead of starting a new one.
- **`category('customers')`**: the inbox and its filters show it as a customer request, and one rule can handle all of them.
- **`url(…)`**: shown as **Open link**, so the push takes you straight to the request in your admin.
- **`action('Reply by email', …)`** and **`action('Call', …)`**: two buttons on the message, also on the iPhone notification when it shows the text. `mailto:` opens your mail app addressed to the customer and `tel:` calls them; nothing opens until you tap.
- **`light()`**: a customer request isn’t an outage. To push it even when your push threshold is higher, add `->priority('high')`.

Keep `toHonk()` deterministic, with no `now()` inside: a queued retry must send the same payload, or Honk answers `409 idempotency_conflict`.

## 2. Send it where the request is stored

```php
// app/Http/Controllers/QuoteController.php
public function store(StoreQuoteRequest $request)
{
    $quote = CustomerRequest::create($request->validated());

    // queued, after the transaction commits: the customer never waits for Honk
    Notification::route('honk', null)->notify(new CustomerRequested($quote));

    return to_route('quote.thanks');
}
```

`Notification::route('honk', null)` sends without a user model. If your admins are users, `$admin->notify(…)` works too.

## 3. On your iPhone

The request arrives as a push with its title and the first lines of the message. On iPhones with Apple Intelligence, Honk lists the key details (who, what they want, the budget, the deadline), each showing which message it came from, and drafts a reply you can read, edit and copy into your own mail app. Honk never sends anything for you. All of it runs on the device: the request is never sent anywhere for AI, and the original text is always one tap away.

The daily summary can start your morning with “5 new customer requests,” and on Apple Watch, Double Tap marks a request handled once you’ve answered it.

## The same in other languages

Every library has this recipe in its README, with one group and one idempotency key per request:

- [Node.js](https://honk-me.app/integrations/node#recipe): sent without awaiting, so the response isn’t delayed.
- [Go](https://honk-me.app/integrations/go#recipe): in a goroutine with its own timeout.
- [Swift with Vapor](https://honk-me.app/integrations/swift#recipe), [Kotlin and Java with Spring Boot](https://honk-me.app/integrations/kotlin#recipe) and [Rust](https://honk-me.app/integrations/rust#recipe).
- [n8n](https://honk-me.app/integrations/n8n#send) when the form posts to a webhook.

## Mind the content

Honk keeps the message on its server for 3, 14 or 30 days, depending on your plan, and shows it in notifications. Send what you need to act on the request, not the customer’s whole record. For projects with sensitive content, set the push preview to **Generic**: notifications then show no content, and the details stay in the app.
