Documentation

Rich notifications

Add a hero image and a custom sound to push notifications, and wire the client side to render them.

A rich push carries two extras beyond title and body: an image and a custom sound. Configure both in the campaign composer or a journey Send push node, or send them in content via the API.

info

Note

Payghaam only carries the image URL and the sound name. Images are fetched at delivery time, but sound files must be bundled inside your app — they cannot be streamed from a URL.

Sending via the API

Every field is optional. Include only what you need:

POST /api/projects/:id/messages
{
  "content": {
    "title": "Weekend sale",
    "body": "20% off, today only",
    "imageUrl": "https://cdn.yourapp.com/media/sale.png",
    "soundIos": "chime.caf",
    "soundAndroid": "chime"
  }
}

Image

Paste an HTTPS URL or upload a file to the media library from the composer's Image field. Uploaded files are hosted on your configured storage/CDN and reused across sends.

  • iOS — delivered as a notification attachment. The image shows as a thumbnail on the banner and full-size when the notification is expanded. Requires the Notification Service Extension from iOS setup.
  • Android — delivered as a BigPictureStyle: a thumbnail when collapsed and a full-width picture when expanded. No extra setup beyond the SDK.

Custom sound

iOS and Android name sounds differently, so there are two independent fields. Fill in whichever platforms you target — a blank field falls back to the system default.

FieldPlatformFormatExample
soundIosiOS (APNs)filename with extensionchime.caf
soundAndroidAndroid (FCM)res/raw name, no extensionchime

iOS implementation

  1. Add a short audio file (.caf, .aiff, .wav, ≤30s) to the app target's Copy Bundle Resources.
  2. Enter the filename with extension in the iOS sound field. iOS plays it automatically from aps.sound — no code changes needed.

Android implementation

On Android 8+ a sound is a property of the notification channel and is locked once the channel is created, so a custom sound means routing to a channel that has it. Add the file to android/app/src/main/res/raw/ (lowercase, no spaces), enter its extensionless name in the Android sound field, then read ek_sound from the data payload and create a per-sound channel:

PayghaamFirebaseMessagingService.kt
// In PayghaamFirebaseMessagingService.showNotification(...)
val soundName = message.data["ek_sound"]           // e.g. "chime"
val channelId = if (soundName.isNullOrBlank()) "payghaam_default"
                else "payghaam_sound_$soundName"

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
    nm.getNotificationChannel(channelId) == null) {
  val channel = NotificationChannel(
    channelId, "Notifications", NotificationManager.IMPORTANCE_HIGH,
  )
  if (!soundName.isNullOrBlank()) {
    // soundAndroid arrives already extension-free (a res/raw resource name).
    val uri = Uri.parse("android.resource://$packageName/raw/$soundName")
    val attrs = AudioAttributes.Builder()
      .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
      .setUsage(AudioAttributes.USAGE_NOTIFICATION)
      .build()
    channel.setSound(uri, attrs)
  }
  nm.createNotificationChannel(channel)
}
warning

Warning

A channel's sound cannot change after creation. If you swap the audio file, bump the resource name (chimechime_v2) so a fresh channel is created.

Full platform walkthrough: iOS setup and Android setup.