Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions lib/resend/broadcasts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ def get(broadcast_id = "")
path = "broadcasts/#{broadcast_id}"
Resend::Request.new(path, {}, "get").perform
end

# https://resend.com/docs/api-reference/broadcasts/list-broadcast-recipients
# @param broadcast_id [String] the broadcast id
# @param params [Hash] the parameters
# @option params [String] :type the recipient event type to filter by (required):
# sent, delivered, opened, clicked, bounced, complained, unsubscribed, suppressed
# @option params [String] :email filter recipients by email address (optional)
# @option params [String] :bounce_type filter bounced recipients by bounce type (optional,
# only valid when type is bounced): permanent, transient, undetermined
# @option params [Integer] :limit the maximum number of results to return (optional)
# @option params [String] :after the cursor for pagination (optional)
# @option params [String] :before the cursor for pagination (optional)
def recipients(broadcast_id = "", params = {})
raise ArgumentError, "type is required" if params[:type].nil?

base_path = "broadcasts/#{broadcast_id}/recipients"
path = Resend::PaginationHelper.build_paginated_path(base_path, params)
Resend::Request.new(path, {}, "get").perform
end
end
end
end
135 changes: 135 additions & 0 deletions spec/broadcasts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,141 @@
end
end

describe "recipients" do
it "should raise when type is missing" do
Comment thread
dielduarte marked this conversation as resolved.
expect do
Resend::Broadcasts.recipients("559ac32e-9ef5-46fb-82a1-b76b840c0f7b", {})
end.to raise_error(ArgumentError, "type is required")
end

it "should list recipients for a basic event type" do
resp = {
"object": "list",
"has_more": false,
"data": [
{
"id" => "b2Zmc2V0OjA",
"contact_id" => "e169aa45-1ecf-4183-9955-b1499d5701d3",
"email" => "carter@example.com"
}
]
}
expect(Resend::Request).to receive(:new).with(
"broadcasts/559ac32e-9ef5-46fb-82a1-b76b840c0f7b/recipients?type=sent",
{},
"get"
).and_call_original
allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp)
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.

recipients = Resend::Broadcasts.recipients(
"559ac32e-9ef5-46fb-82a1-b76b840c0f7b",
{ type: "sent" }
)

expect(recipients[:object]).to eql("list")
expect(recipients[:has_more]).to eql(false)
expect(recipients[:data].length).to eql(1)
expect(recipients[:data][0]["id"]).to eql("b2Zmc2V0OjA")
expect(recipients[:data][0]["contact_id"]).to eql("e169aa45-1ecf-4183-9955-b1499d5701d3")
expect(recipients[:data][0]["email"]).to eql("carter@example.com")
end

it "should list recipients with count for opened type" do
resp = {
"object": "list",
"has_more": false,
"data": [
{
"id" => "b2Zmc2V0OjA",
"contact_id" => "e169aa45-1ecf-4183-9955-b1499d5701d3",
"email" => "carter@example.com",
"count" => 3
}
]
}
allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp)

recipients = Resend::Broadcasts.recipients(
"559ac32e-9ef5-46fb-82a1-b76b840c0f7b",
{ type: "opened" }
)

expect(recipients[:data][0]["count"]).to eql(3)
end

it "should list recipients with clicked_links for clicked type" do
resp = {
"object": "list",
"has_more": false,
"data": [
{
"id" => "b2Zmc2V0OjA",
"contact_id" => "e169aa45-1ecf-4183-9955-b1499d5701d3",
"email" => "carter@example.com",
"count" => 2,
"clicked_links" => [
{ "url" => "https://resend.com/pricing", "clicks" => 2 }
]
}
]
}
allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp)

recipients = Resend::Broadcasts.recipients(
"559ac32e-9ef5-46fb-82a1-b76b840c0f7b",
{ type: "clicked" }
)

expect(recipients[:data][0]["count"]).to eql(2)
expect(recipients[:data][0]["clicked_links"]).to eql(
[{ "url" => "https://resend.com/pricing", "clicks" => 2 }]
)
end

it "should list recipients with bounce_type for bounced type" do
resp = {
"object": "list",
"has_more": false,
"data": [
{
"id" => "b2Zmc2V0OjA",
"contact_id" => nil,
"email" => "carter@example.com",
"bounce_type" => "permanent"
}
]
}
expect(Resend::Request).to receive(:new).with(
"broadcasts/559ac32e-9ef5-46fb-82a1-b76b840c0f7b/recipients?type=bounced&bounce_type=permanent",
{},
"get"
).and_call_original
allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp)

recipients = Resend::Broadcasts.recipients(
"559ac32e-9ef5-46fb-82a1-b76b840c0f7b",
{ type: "bounced", bounce_type: "permanent" }
)

expect(recipients[:data][0]["contact_id"]).to eql(nil)
expect(recipients[:data][0]["bounce_type"]).to eql("permanent")
end

it "should raise when broadcast is not found" do
resp = {
"statusCode" => 404,
"name" => "not_found",
"message" => "Broadcast not found"
}
allow(resp).to receive(:body).and_return(resp)
allow(HTTParty).to receive(:send).and_return(resp)

expect do
Resend::Broadcasts.recipients("missing-id", { type: "sent" })
end.to raise_error(Resend::Error::NotFoundError, /Broadcast not found/)
end
end

describe "get broadcast" do

it "should retrieve a broadcast" do
Expand Down