Accrue.Router (accrue v1.5.0)

Copy Markdown View Source

Router helpers for mounting Accrue webhook endpoints.

Usage (Phoenix router)

import Accrue.Router

pipeline :accrue_webhook_raw_body do
  plug Plug.Parsers,
    parsers: [:json],
    pass: ["*/*"],
    json_decoder: Jason,
    body_reader: {Accrue.Webhook.CachingBodyReader, :read_body, []},
    length: 1_000_000
end

scope "/webhooks" do
  pipe_through :accrue_webhook_raw_body
  accrue_webhook "/stripe", :stripe
end

Apple App Store Server Notifications V2 use a dedicated route-scoped body reader whose parser limit matches the notification plug's 256 KiB default:

pipeline :accrue_apple_notifications_raw_body do
  plug Plug.Parsers,
    parsers: [:json],
    pass: ["*/*"],
    json_decoder: Jason,
    body_reader: {Accrue.Webhook.CachingBodyReader, :read_body, []},
    length: 262_144
end

scope "/webhooks" do
  pipe_through :accrue_apple_notifications_raw_body
  accrue_apple_notifications "/apple", verifier_config: apple_verifier_config,
    rate_limiter: &MyApp.AppleRateLimiter.check/1
end

Multi-endpoint (Phase 4 Connect ready, D2-18)

The macro accepts a processor atom. Calling accrue_webhook/2 multiple times with different processors works natively:

scope "/webhooks" do
  pipe_through :accrue_webhook_raw_body
  accrue_webhook "/stripe", :stripe
  accrue_webhook "/connect", :stripe_connect
end

Each resolves to its own signing secret via Accrue.Config.

Entitlement guards (controller pipeline)

require_feature/1 and require_plan/1 are single-arg sugar over Accrue.Plug.RequireEntitlement for the common "gate one feature / plan" case in a controller's plug pipeline:

import Accrue.Router

defmodule MyAppWeb.ReportsController do
  use MyAppWeb, :controller

  require_feature :reports      # plug Accrue.Plug.RequireEntitlement, feature: :reports
  require_plan :pro             # plug Accrue.Plug.RequireEntitlement, plan: :pro
  # ... actions
end

For advanced overrides (status:, on_deny:, billable:) use the explicit plug form directly:

plug Accrue.Plug.RequireEntitlement, feature: :reports, on_deny: {:redirect, "/pricing"}

Summary

Functions

Mounts the Apple App Store Server Notifications V2 plug at path.

Mounts the Accrue webhook plug at the given path for the specified processor.

Gates a controller pipeline on a single feature.

Gates a controller pipeline on an active plan (an atom plan key or a price_id String).

Functions

accrue_apple_notifications(path, opts)

(macro)

Mounts the Apple App Store Server Notifications V2 plug at path.

opts are host-supplied Accrue.Entitlements.Apple.NotificationPlug options, including :verifier_config and optional :rate_limiter. Must be called inside a route-scoped Plug.Parsers pipeline using Accrue.Webhook.CachingBodyReader.read_body/2, with the parser :length matching :max_body_bytes (262,144 by default); otherwise the plug returns a retryable 503 without verifying or persisting the notification.

accrue_webhook(path, processor)

(macro)

Mounts the Accrue webhook plug at the given path for the specified processor.

Expands to forward path, Accrue.Webhook.Plug, processor: processor. Must be called inside a scope that pipes through a pipeline containing Plug.Parsers with body_reader: {Accrue.Webhook.CachingBodyReader, :read_body, []}.

require_feature(feature)

(macro)

Gates a controller pipeline on a single feature.

Expands to plug Accrue.Plug.RequireEntitlement, feature: feature. For status: / on_deny: / billable: overrides, use the explicit plug Accrue.Plug.RequireEntitlement, … form instead.

require_plan(plan)

(macro)

Gates a controller pipeline on an active plan (an atom plan key or a price_id String).

Expands to plug Accrue.Plug.RequireEntitlement, plan: plan. For status: / on_deny: / billable: overrides, use the explicit plug Accrue.Plug.RequireEntitlement, … form instead.