Developer docs

Customer context

Bring each customer's orders, subscriptions, and licenses into the conversation sidebar — live from your store (EDD, WooCommerce, FluentCart, Shopify) or any custom app.

Customer context pulls a customer’s commerce history — orders, subscriptions, licenses, sites, and payment method — into the conversation sidebar, fetched live from your store when an agent opens the ticket. No tab-switching, no stale copies.

Supported platforms

PlatformHowStatus
Easy Digital DownloadsReplyPlex WordPress pluginLive
WooCommerceReplyPlex WordPress pluginLive
FluentCartReplyPlex WordPress pluginLive (pending live-store smoke test)
Custom app (pull)Your own endpoint serving the context contractLive
Custom app (push)PUT /public/v1/customers/{email}/context — no endpoint neededLive
ShopifyHosted OAuth + Admin APIComing

WordPress carts (EDD / Woo / FluentCart) are served by one companion plugin that detects which carts are installed and returns already-normalized data — so adding Woo or FluentCart is plugin work, not a new ReplyPlex integration.

How it works

  • Per-org connections — one set of store connections is shared across all the org’s inboxes.
  • On-demand, nothing stored — context is fetched when the sidebar opens (GET /v1/conversations/:id/commerce), resolved in parallel across only the connected providers, with a short cache (~60s) and a per-call timeout (~15s). Each connection renders one card; a failing lookup is isolated to its own card. The one deliberate exception is pushed context, which is stored with a TTL and clearly captioned as pushed.
  • Read-only first — write-actions (refund / resend / cancel) are planned behind the same seam.

Connect a WordPress store

  1. Install the ReplyPlex plugin. Build the zip with pnpm build:wp-plugin (→ integrations/replyplex-wp/dist/replyplex.zip) and install it in WordPress.
  2. Generate a key in WP-admin and copy your site URL.
  3. In ReplyPlex, go to Manage → Integrations, paste the site URL + key, and connect. ReplyPlex calls GET {site}/wp-json/replyplex/v1/ping with the key to verify before saving.

The plugin contract

The companion plugin exposes a small, versioned REST API. ReplyPlex calls it server-side with the paired key:

GET {site}/wp-json/replyplex/v1/customer?email=<email>
Authorization: Bearer <apiKey>

The plugin does all per-cart mapping and returns the normalized shape:

{
  "found": true,
  "summary": { "name": "James Carter", "ordersCount": 12, "totalSpent": "1,234.00 USD" },
  "carts": [
    {
      "provider": "edd",
      "label": "Easy Digital Downloads",
      "sections": [
        {
          "title": "Purchases",
          "items": [
            {
              "title": "Pro License",
              "subtitle": "#1234",
              "status": "completed",
              "amount": "99.00 USD",
              "date": "2026-01-02",
              "url": "https://site/wp-admin/edit.php?post=1234"
            }
          ]
        },
        { "title": "Licenses", "items": [] }
      ]
    }
  ]
}

found: false (with empty carts) renders a “No customer found” state for that connection.

Connect a custom app

Your product doesn’t have to be a WordPress cart. Any service that can host two HTTPS endpoints can feed the sidebar — subscriptions, licenses, plans, account status, whatever your customers ask about.

  1. Serve the two endpoints below from a base URL of your choice.
  2. In ReplyPlex, go to Manage → Integrations → Connect a custom app and enter a label, the endpoint URL, and the API key your endpoint checks. ReplyPlex calls GET {base}/ping to verify before saving.

The contract

Both endpoints receive your key as a Bearer token — compare it in constant time and reply with JSON.

GET {base}/ping
Authorization: Bearer <apiKey>

Respond { "ok": true } when the key is valid.

GET {base}/customer?email=<urlencoded email>
Authorization: Bearer <apiKey>

Respond with the same normalized shape the WordPress plugin uses — cards and carts are both accepted as the array key:

{
  "found": true,
  "summary": { "name": "James Carter", "ordersCount": 3, "totalSpent": "297.00 USD" },
  "cards": [
    {
      "label": "My App",
      "sections": [
        {
          "title": "Subscription",
          "items": [
            {
              "title": "Agency plan",
              "status": "active",
              "amount": "99.00 USD / year",
              "date": "2026-01-02",
              "url": "https://admin.myapp.com/customers/123"
            }
          ]
        }
      ]
    }
  ]
}
  • found: false (or an empty array) renders a “No customer found” state for that connection.
  • Sections that don’t match the shape are dropped individually — one malformed row never takes down the card.
  • Items support the full shape from the plugin contract: subtitle, status, amount, date, url, plus meta (labeled key/value rows, optionally linked) and links (a labeled list, e.g. activated sites).

Push context (no endpoint required)

If your product can’t host a public endpoint, push the cards instead: send them to the developer API and they render in the sidebar beside live store lookups — captioned “Pushed <time>” so agents always know they’re looking at stored context, not a live lookup. Pushed cards feed AI drafting the same way pull cards do.

Requires an API key with the write scope (see Authentication). The email in the path is URL-encoded.

PUT /public/v1/customers/{email}/context
Authorization: Bearer rp_live_…
Content-Type: application/json
{
  "source": "Templately",
  "ttlSeconds": 604800,
  "cards": [
    {
      "label": "Subscription",
      "summary": "Pro — annual",
      "sections": [
        { "title": "Plan", "items": [ { "title": "Pro", "status": "active" } ] }
      ]
    }
  ]
}
  • source is your product’s name — it attributes the cards and is the replacement key: each PUT replaces that source’s cards for that customer, so push the full current set each time.
  • TTL: ttlSeconds is optional — default 7 days, maximum 30 days. Cards disappear at the returned expiresAt unless refreshed; push on change or on a timer.
  • Limits: at most 10 cards and 32 KB serialized per push. sections/items use the same shapes as the pull contract above.
  • Response: { "ok": true, "expiresAt": "…" }.

To remove your cards immediately (uninstall, disconnect):

DELETE /public/v1/customers/{email}/context?source=Templately
Authorization: Bearer rp_live_…

Idempotent — deleting an already-clear slice succeeds.

Security

  • Credentials encrypted at rest (AES-256-GCM, key from INTEGRATIONS_SECRET); never returned to the client, redacted from logs.
  • Outbound calls are server-side only, https-only, SSRF-guarded (private/loopback hosts rejected), time-bounded (~15s), and cached (~60s).
  • Per-org isolation; pairing verified via /ping before the connection is saved.