Send emails and transactions via the Adapty Mail API

The Adapty Mail API lets you send user profiles and transactions to Adapty Mail directly from your server, without routing data through the Adapty SDK. Use it when you want to:

  • Add subscribers when you don’t have a base in Adapty Mail yet.
  • Reuse the subscriber base from your other apps.
  • Feed Adapty Mail server-to-server, with your backend as the source of truth.

API or SDK? Most apps send data to Adapty Mail through the Adapty SDK, which collects emails and purchases automatically. Choose the API when your app has no Adapty SDK, when the data already lives on your server, or when you import subscribers from another source.

Before you start

Finish setting up Adapty Mail before you send data — that means a campaign, segments (if you need them), a web paywall, and a launched flow. Adapty Mail sends emails only to profiles created after this setup is complete; profiles you send earlier won’t receive any emails. Follow Get started with Adapty Mail first, then return here.

You also need your API key and base URL:

  • Secret API key: In Adapty Mail, go to Settings and copy your secret API key. The key is project-specific, so the API knows which project the data belongs to.
  • Base URL: All requests go to https://api-mail.adapty.io.
  • Authentication: Send the key in the Authorization header as Bearer {your_secret_api_key}.

Get explicit consent before you collect emails and send them to Adapty Mail. You are responsible for compliance with GDPR, CAN-SPAM, and similar regulations in your markets.

Send user profiles

A profile carries the user’s email and attributes. To create or update one, send a POST request to /api/v1/profile/save/.

Three fields are required:

  • A stable external_profile_id that your app or backend owns
  • The email Adapty Mail delivers campaigns to
  • external_created_at — the user creation time, which you can use in segments

Always send a stable external_profile_id, never an anonymous or per-install value. Adapty Mail uses it to link emails, clicks, and purchases to one profile.

curl --request POST \
  --url 'https://api-mail.adapty.io/api/v1/profile/save/' \
  --header 'Authorization: Bearer {your_secret_api_key}' \
  --header 'Content-Type: application/json' \
  --data '{
    "external_profile_id": "user_12345",
    "external_created_at": "2026-06-01T10:30:00Z",
    "email": "[email protected]",
    "country": "US",
    "custom_attributes": {
      "plan": "trial"
    }
  }'

See the Save profile reference for every available field.

Send transaction events

A profile with an email is enough to reach users in the never purchased flow. Users in every other flow also need transaction events.

Every flow except never purchased is driven by purchase history. Send a profile’s transaction events as you handle purchases, renewals, and cancellations, so Adapty Mail can place it in the right flow. Transaction events also power revenue attribution. Skip them only if you run never purchased campaigns exclusively.

To record a transaction, send a POST request to /api/v1/profile/transaction-event/save/. Use the same external_profile_id you sent with the profile so Adapty Mail links the transaction to the right user.

curl --request POST \
  --url 'https://api-mail.adapty.io/api/v1/profile/transaction-event/save/' \
  --header 'Authorization: Bearer {your_secret_api_key}' \
  --header 'Content-Type: application/json' \
  --data '{
    "event_type": "subscription_started",
    "event_id": "evt_abc123",
    "event_datetime": "2026-06-10T14:20:05Z",
    "external_profile_id": "user_12345",
    "store": "app_store",
    "store_product_id": "premium_monthly",
    "store_transaction_id": "1000000123456789",
    "store_original_transaction_id": "1000000123456789",
    "purchased_at": "2026-06-10T14:20:00Z",
    "originally_purchased_at": "2026-06-10T14:20:00Z",
    "price_usd": "9.99"
  }'

See the Save transaction event reference for every available field.

Map your events to flows

Send the event_type that matches what happened. Adapty Mail derives the profile’s state from its event history and routes it to the matching flow.

event_typeSend it whenFlow
subscription_startedA user starts a new subscription.Active — no re-engagement flow
subscription_renewedA subscription auto-renews.Active — no re-engagement flow
subscription_renewal_reactivatedA user turns auto-renew back on.Active — no re-engagement flow
non_subscription_purchaseA user makes a one-time purchase.Active — no re-engagement flow
subscription_renewal_cancelledA user turns off auto-renew (still active until expiry).Renewal cancelled
billing_issue_detectedA renewal payment fails.Billing issue
entered_grace_periodPayment fails but the user is still in a grace period.Billing issue
subscription_expiredA subscription lapses and access ends.Expired
subscription_refundedA subscription purchase is refunded.Refunded
non_subscription_purchase_refundedA one-time purchase is refunded.Refunded