-
Notifications
You must be signed in to change notification settings - Fork 10
feat: add domain claims endpoints #194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require_relative "../lib/resend" | ||
|
|
||
| raise if ENV["RESEND_API_KEY"].nil? | ||
|
|
||
| Resend.api_key = ENV["RESEND_API_KEY"] | ||
|
|
||
| def claim_domain | ||
| params = { | ||
| name: "example.com", | ||
| region: "us-east-1" | ||
| } | ||
| claim = Resend::Domains::Claims.create(params) | ||
| puts "Created domain claim: #{claim[:id]}" | ||
| puts "Status: #{claim[:status]}" | ||
|
|
||
| record = claim[:record] | ||
| puts "Add this TXT record to prove ownership: #{record[:name]} = #{record[:value]}" if record | ||
|
|
||
| # Get: poll the claim until the TXT record has been added and verification can run. | ||
| retrieved = Resend::Domains::Claims.get(claim[:domain_id]) | ||
| puts "Retrieved domain claim status: #{retrieved[:status]}" | ||
|
|
||
| # Verify: trigger asynchronous DNS verification and ownership transfer. | ||
| verified = Resend::Domains::Claims.verify(claim[:domain_id]) | ||
| puts "Verification triggered, claim status: #{verified[:status]}" | ||
| end | ||
|
|
||
| claim_domain | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Resend | ||
| module Domains | ||
| # Domain Claims API wrapper | ||
| module Claims | ||
| class << self | ||
| # | ||
| # Start a claim for a domain that another Resend account has already verified. | ||
| # The domain is recreated under your account with fresh DKIM keys, so the | ||
| # previous account's DNS records cannot be reused. Returns a TXT record to add | ||
| # to your DNS to prove ownership. Uses the same request body as creating a domain. | ||
| # | ||
| # @param params [Hash] the parameters | ||
| # @option params [String] :name the name of the domain you want to claim (required) | ||
| # @option params [String] :region the region where emails will be sent from. | ||
| # Possible values: 'us-east-1' | 'eu-west-1' | 'sa-east-1' | 'ap-northeast-1' | ||
| # @option params [String] :custom_return_path subdomain for the Return-Path address (default 'send') | ||
| # @option params [String] :tracking_subdomain the custom subdomain used for click and open tracking links | ||
| # @option params [Boolean] :click_tracking track clicks within the body of each HTML email | ||
| # @option params [Boolean] :open_tracking track the open rate of each email | ||
| # | ||
| # https://resend.com/docs/api-reference/domains/claim-domain | ||
| def create(params) | ||
| path = "domains/claim" | ||
| Resend::Request.new(path, params, "post").perform | ||
| end | ||
|
|
||
| # | ||
| # Retrieve the latest claim for the placeholder domain created by the claim. | ||
| # | ||
| # @param domain_id [String] the ID of the placeholder domain created by the claim | ||
| # | ||
| # https://resend.com/docs/api-reference/domains/get-domain-claim | ||
| def get(domain_id = "") | ||
| path = "domains/#{domain_id}/claim" | ||
| Resend::Request.new(path, {}, "get").perform | ||
| end | ||
|
|
||
| # | ||
| # Trigger asynchronous DNS verification and ownership transfer for a domain claim. | ||
| # The claim stays 'pending' while verification runs; poll `get` for status. Once | ||
| # 'completed', the transferred domain has new DKIM records that must be added to | ||
| # DNS and verified via Resend::Domains.verify. | ||
| # | ||
| # @param domain_id [String] the ID of the placeholder domain created by the claim | ||
| # | ||
| # https://resend.com/docs/api-reference/domains/verify-domain-claim | ||
| def verify(domain_id = "") | ||
| path = "domains/#{domain_id}/claim/verify" | ||
| Resend::Request.new(path, {}, "post").perform | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| RSpec.describe "Domains::Claims" do | ||
| before do | ||
| Resend.configure do |config| | ||
| config.api_key = "re_123" | ||
| end | ||
| end | ||
|
|
||
| describe "create" do | ||
| it "should start a domain claim" do | ||
| resp = { | ||
| object: "domain_claim", | ||
| id: "dacf4072-4119-4d88-932f-6c6126d3a9d1", | ||
| name: "example.com", | ||
| status: "pending", | ||
| domain_id: "d91cd9bd-1176-453e-8fc1-35364d380206", | ||
| region: "us-east-1", | ||
| record: { | ||
| type: "TXT", | ||
| name: "example.com", | ||
| value: "resend-domain-verification=3f8a1c2d4e5b6a7f8091a2b3c4d5e6f7", | ||
| ttl: "Auto" | ||
| }, | ||
| blocked_reason: nil, | ||
| failure_reason: nil, | ||
| created_at: "2026-06-16T17:12:02.059593+00:00", | ||
| expires_at: "2026-06-23T17:12:02.059593+00:00" | ||
| } | ||
|
|
||
| params = { name: "example.com" } | ||
| allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) | ||
| claim = Resend::Domains::Claims.create(params) | ||
| expect(claim[:id]).to eql("dacf4072-4119-4d88-932f-6c6126d3a9d1") | ||
| expect(claim[:object]).to eql("domain_claim") | ||
| expect(claim[:status]).to eql("pending") | ||
| expect(claim[:domain_id]).to eql("d91cd9bd-1176-453e-8fc1-35364d380206") | ||
| expect(claim[:record][:type]).to eql("TXT") | ||
| expect(claim[:record][:value]).to eql("resend-domain-verification=3f8a1c2d4e5b6a7f8091a2b3c4d5e6f7") | ||
| end | ||
|
|
||
| it "should pass all options in the request body" do | ||
| resp = { object: "domain_claim", id: "dacf4072-4119-4d88-932f-6c6126d3a9d1", status: "pending" } | ||
|
|
||
| params = { | ||
| name: "example.com", | ||
| region: "us-east-1", | ||
| custom_return_path: "send", | ||
| open_tracking: true, | ||
| click_tracking: false, | ||
| tracking_subdomain: "links" | ||
| } | ||
|
|
||
| expect(Resend::Request).to receive(:new).with("domains/claim", params, "post").and_call_original | ||
| allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) | ||
| Resend::Domains::Claims.create(params) | ||
| end | ||
| end | ||
|
|
||
| describe "get" do | ||
| it "should retrieve a domain claim" do | ||
| resp = { | ||
| object: "domain_claim", | ||
| id: "dacf4072-4119-4d88-932f-6c6126d3a9d1", | ||
| name: "example.com", | ||
| status: "blocked", | ||
| domain_id: "d91cd9bd-1176-453e-8fc1-35364d380206", | ||
| region: "us-east-1", | ||
| blocked_reason: "grace_period", | ||
| failure_reason: nil, | ||
| created_at: "2026-06-16T17:12:02.059593+00:00", | ||
| expires_at: "2026-06-23T17:12:02.059593+00:00" | ||
| } | ||
| allow(resp).to receive(:body).and_return(resp) | ||
| allow(HTTParty).to receive(:send).and_return(resp) | ||
|
|
||
| claim = Resend::Domains::Claims.get(resp[:domain_id]) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The Prompt for AI agents |
||
|
|
||
| expect(claim[:id]).to eql("dacf4072-4119-4d88-932f-6c6126d3a9d1") | ||
| expect(claim[:status]).to eql("blocked") | ||
| expect(claim[:blocked_reason]).to eql("grace_period") | ||
| end | ||
| end | ||
|
|
||
| describe "verify" do | ||
| it "should trigger verification for a domain claim" do | ||
| resp = { | ||
| object: "domain_claim", | ||
| id: "dacf4072-4119-4d88-932f-6c6126d3a9d1", | ||
| name: "example.com", | ||
| status: "pending", | ||
| domain_id: "d91cd9bd-1176-453e-8fc1-35364d380206", | ||
| region: "us-east-1" | ||
| } | ||
| allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) | ||
| claim = Resend::Domains::Claims.verify("d91cd9bd-1176-453e-8fc1-35364d380206") | ||
| expect(claim[:id]).to eql("dacf4072-4119-4d88-932f-6c6126d3a9d1") | ||
| expect(claim[:status]).to eql("pending") | ||
| end | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: This example can print blank/wrong TXT record fields because nested response objects are accessed with symbol keys instead of string keys. Using
record['name']/record['value']keeps the sample aligned with actual response shape.(Based on your team's feedback about nested response key access conventions.) .
View Feedback
Prompt for AI agents