---
title: "The Headless Dashboard Initiative"
slug: headless-dashboard-initiative
description: "The path to make everything available through the MCP, CLI, or any SDK."
created_at: "2026-09-22"
updated_at: "2026-09-22"
image: https://cdn.resend.com/posts/headless-dashboard-initiative.jpg
humans: ["zeno-rocha"]
category: "engineering"
featured: true
---

Developer tools should give developers power.

You should have control that's predictable and accessible from any surface you prefer: **the dashboard, MCP, CLI, or the API**. Humans and agents alike should have equal access with the developer as the operator.

## Our journey

Earlier this summer, we mapped several interactions that required the Resend Dashboard and started slowly closing the gap for each one.

<Tweet id="2077034980828754024" />

Today, I'm excited to share how far we've come. Most of what you manage in the dashboard is now accessible through the MCP, CLI, or the API. That's the direction we're committed to, and it's what we mean by headless:

> Everything the dashboard can do should also be available programmatically.

The initiative lets you:

- embed full email analytics in your app
- build custom Broadcast experiences for your customers
- manage your Resend account with your agent
- create personalized dashboards and reports

We'll make the dashboard best-in-class, while also **committing to full headless operation for every future entity**. Use the dashboard when it makes sense. Build your own custom experiences when it doesn't.

## What you can use now

While many on the team have contributed to get us to this point, three people in particular deserve a special call-out: <Human id="diel-duarte" />, <Human id="gabriel-miranda" />, and <Human id="felipe-freitag" />.

Here are the key changes we've released in the last several months.

1. [Email Metrics API](#1-email-metrics-api)
2. [Headless Webhook API](#2-headless-webhook-api)
3. [Cancel Broadcast API](#3-cancel-broadcast-api)
4. [Share Email API](#4-share-email-api)
5. [Duplicate Automation API](#5-duplicate-automation-api)
6. [Update Segment API](#6-update-segment-api)
7. [List Clicked Links API](#7-list-clicked-links-api)
8. [Update API Key Name](#8-update-api-key-name)
9. [Duplicate Broadcast API](#9-duplicate-broadcast-api)

### 1. Email Metrics API

The Email Metrics API returns deliverability and engagement data for your emails, from send volume to unsubscribe rate, grouped or filtered by period, domain, broadcast, or email. It powers:
- custom dashboards showing your deliverability and reputation metrics
- reports that summarize campaign performance
- alerts that fire when bounce or complaint rates spike

A request with no parameters returns every metric over the past 7 days.

<CodeTabs codeHeight={250}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data } = await resend.emails.metrics()
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$metrics = $resend->emails->metrics();
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

metrics = resend.Emails.metrics()
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

metrics = Resend::Emails.metrics
```

```go
import "github.com/resend/resend-go/v4"

func main() {
  client := resend.NewClient("re_xxxxxxxxx")

  metrics, _ := client.Emails.Metrics()
}
```

```rust
use resend_rs::types::GetEmailMetricsOptions;
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _metrics = resend.emails.metrics(GetEmailMetricsOptions::default()).await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

EmailsMetricsResponse data = resend.emails().metrics();
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

await resend.EmailMetricsAsync();
```

```curl
curl -X GET 'https://api.resend.com/emails/metrics' \
     -H 'Authorization: Bearer re_xxxxxxxxx'
```

```cli
resend emails metrics
```
</CodeTabs>

Learn more about the [Email Metrics API](/docs/api-reference/emails/get-metrics) or read the changelog.

<LinkCard
  title="Email Metrics API Changelog"
  description="Read the full changelog for the Email Metrics API."
  url="/changelog/email-metrics-api"
  image="https://cdn.resend.com/posts/email-metrics-api.jpg"
/>

### 2. Headless Webhook API

Everything the webhook detail page does is now available in the API, every [SDK](/docs/sdks), the MCP server, and the CLI:

- [List Events](/docs/api-reference/webhooks/list-events): every event delivered to a webhook, with its delivery status
- [Retrieve Event](/docs/api-reference/webhooks/get-event): the exact payload we sent to your endpoint
- [List Attempts](/docs/api-reference/webhooks/list-event-attempts): every attempt with the status code and body your endpoint returned
- [Replay Event](/docs/api-reference/webhooks/replay-event): queue another delivery of a webhook event
- [Rotate Signing Secret](/docs/api-reference/webhooks/rotate-signing-secret): get a new secret without opening the dashboard

Together these let you list failed events and replay them in a loop, page your team when deliveries fail, rotate secrets from CI, or connect the MCP server and ask your agent what failed.

Start by listing the events delivered to a webhook. Each one carries a delivery status of `success`, `failed`, `attempting`, or `pending`.

<CodeTabs codeHeight={250}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.webhooks.events.list({
  webhookId: '4dd369bc-aa82-4ff3-97de-514ae3000ee0',
});
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$events = $resend->webhooks->events->list(
  '4dd369bc-aa82-4ff3-97de-514ae3000ee0'
);
```

```python
import resend

resend.api_key = 're_xxxxxxxxx'

events = resend.Webhooks.list_events(
    webhook_id='4dd369bc-aa82-4ff3-97de-514ae3000ee0'
)
```

```ruby
require 'resend'

Resend.api_key = 're_xxxxxxxxx'

events = Resend::Webhooks.list_events('4dd369bc-aa82-4ff3-97de-514ae3000ee0')
```

```go
import "github.com/resend/resend-go/v4"

client := resend.NewClient("re_xxxxxxxxx")

events, err := client.Webhooks.ListEvents("4dd369bc-aa82-4ff3-97de-514ae3000ee0")
```

```rust
use resend_rs::{list_opts::ListOptions, Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _events = resend
    .webhooks
    .list_events(
      "4dd369bc-aa82-4ff3-97de-514ae3000ee0",
      ListOptions::default(),
    )
    .await?;

  Ok(())
}
```

```java
import com.resend.*;
import com.resend.core.exception.ResendException;
import com.resend.services.webhooks.model.ListWebhookEventsResponseSuccess;

public class Main {
    public static void main(String[] args) throws ResendException {
        Resend resend = new Resend("re_xxxxxxxxx");

        ListWebhookEventsResponseSuccess events = resend.webhooks().listEvents(
            "4dd369bc-aa82-4ff3-97de-514ae3000ee0"
        );
    }
}
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var resp = await resend.WebhookEventListAsync(
    new Guid( "4dd369bc-aa82-4ff3-97de-514ae3000ee0" )
);
```

```curl
curl -X GET 'https://api.resend.com/webhooks/4dd369bc-aa82-4ff3-97de-514ae3000ee0/events' \
     -H 'Authorization: Bearer re_xxxxxxxxx'
```

```cli
resend webhooks events list 4dd369bc-aa82-4ff3-97de-514ae3000ee0
```
</CodeTabs>

Learn more about the [Headless Webhook API](/docs/api-reference/webhooks/list-events) or read the changelog.

<LinkCard
  title="Headless Webhook API Changelog"
  description="Read the full changelog for the Headless Webhook API."
  url="/changelog/headless-webhook-api"
  image="https://cdn.resend.com/posts/headless-webhook-api.jpg"
/>

### 3. Cancel Broadcast API

The Cancel Broadcast API allows you to cancel a Broadcast programmatically. You can use it to stop a Broadcast when it's still scheduled or during sending before it finishes.

To cancel a Broadcast, use the Broadcast's ID with the cancel endpoint.


<CodeTabs codeHeight={250}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.broadcasts.cancel(
  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->broadcasts->cancel('559ac32e-9ef5-46fb-82a1-b76b840c0f7b');
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

resend.Broadcasts.cancel(id="559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

Resend::Broadcasts.cancel("559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
```

```go
import "github.com/resend/resend-go/v4"

client := resend.NewClient("re_xxxxxxxxx")

canceled, _ := client.Broadcasts.Cancel("559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
```

```rust
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _canceled = resend
    .broadcasts
    .cancel("559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
    .await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

CancelBroadcastResponseSuccess data = resend.broadcasts().cancel("559ac32e-9ef5-46fb-82a1-b76b840c0f7b");
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

await resend.BroadcastCancelAsync( new Guid( "559ac32e-9ef5-46fb-82a1-b76b840c0f7b" ) );
```

```curl
curl -X POST 'https://api.resend.com/broadcasts/559ac32e-9ef5-46fb-82a1-b76b840c0f7b/cancel' \
     -H 'Authorization: Bearer re_xxxxxxxxx' \
     -H 'Content-Type: application/json'
```

```cli
resend broadcasts cancel 559ac32e-9ef5-46fb-82a1-b76b840c0f7b
```
</CodeTabs>

Learn more about the [Cancel Broadcast API](/docs/api-reference/broadcasts/cancel-broadcast) or read the changelog.

<LinkCard
  title="Cancel Broadcast API Changelog"
  description="Read the full changelog for the Cancel Broadcast API."
  url="/changelog/cancel-broadcast-api"
  image="https://cdn.resend.com/posts/cancel-broadcast-api.jpg"
/>

### 4. Share Email API

The Share Email API returns a link to a read-only view of any sent or received email, viewable by anyone with the link. 
- attach a live email preview to a support ticket
- let users open a "view this email" link from your app
- ask your agent to surface the email when reporting on a send

Use the ID of any sent or received email. The API returns the full share URL, and links expire after a duration you control. Pass any duration up to 48 hours, like `10m`, `2 hours`, or `1 day`. It defaults to 48 hours.

<CodeTabs codeHeight={475}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.emails.share(
  '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
  { expiresIn: '2 hours' },
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->emails->share('49a3999c-0ce1-4ea6-ab68-afcd6dc2e794', [
  'expires_in' => '2 hours',
]);
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

resend.Emails.share(
    email_id="49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
    params={"expires_in": "2 hours"},
)
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

Resend::Emails.share(
  "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
  { expires_in: "2 hours" }
)
```

```go
import "github.com/resend/resend-go/v4"

client := resend.NewClient("re_xxxxxxxxx")

shared, _ := client.Emails.Share(
  "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
  &resend.ShareEmailRequest{ExpiresIn: "2 hours"},
)
```

```rust
use resend_rs::types::ShareEmailOptions;
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _shared = resend
    .emails
    .share(
      "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
      ShareEmailOptions::new().with_expires_in("2 hours"),
    )
    .await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

ShareEmailOptions options = ShareEmailOptions.builder()
        .expiresIn("2 hours")
        .build();

ShareEmailResponse data = resend.emails().share("49a3999c-0ce1-4ea6-ab68-afcd6dc2e794", options);
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var shared = await resend.EmailShareAsync(
    new Guid( "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794" ),
    expiresIn: "2 hours" );
```

```curl
curl -X POST 'https://api.resend.com/emails/49a3999c-0ce1-4ea6-ab68-afcd6dc2e794/share' \
     -H 'Authorization: Bearer re_xxxxxxxxx' \
     -H 'Content-Type: application/json' \
     -d $'{
  "expires_in": "2 hours"
}'
```

```cli
resend emails share 49a3999c-0ce1-4ea6-ab68-afcd6dc2e794 --expires-in "2 hours"
```
</CodeTabs>

Learn more about the [Share Email API](/docs/api-reference/emails/share-email) or read the changelog.

<LinkCard
  title="Share Email API Changelog"
  description="Read the full changelog for the Share Email API."
  url="/changelog/share-email-api"
  image="https://cdn.resend.com/posts/share-email-api.jpg"
/>

### 5. Duplicate Automation API

The new duplicate Automation endpoint creates a copy of an existing Automation, named after the original with a `(Copy)` suffix. The copy starts as a disabled draft, so nothing runs until you review and publish it.

To duplicate an Automation, use the Automation's ID with the duplicate endpoint.

<CodeTabs codeHeight={250}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.automations.duplicate(
  'c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd',
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->automations->duplicate('c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd');
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

resend.Automations.duplicate("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd")
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

Resend::Automations.duplicate("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd")
```

```go
import "github.com/resend/resend-go/v4"

client := resend.NewClient("re_xxxxxxxxx")

duplicated, _ := client.Automations.Duplicate("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd")
```

```rust
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _duplicated = resend
    .automations
    .duplicate("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd")
    .await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

DuplicateAutomationResponseSuccess data = resend.automations().duplicate("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd");
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var duplicated = await resend.AutomationDuplicateAsync( new Guid( "c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd" ) );
```

```curl
curl -X POST 'https://api.resend.com/automations/c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd/duplicate' \
     -H 'Authorization: Bearer re_xxxxxxxxx'
```

```cli
resend automations duplicate c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd
```
</CodeTabs>

Learn more about the [Duplicate Automation API](/docs/api-reference/automations/duplicate-automation) or read the changelog.

<LinkCard
  title="Duplicate Automation API Changelog"
  description="Read the full changelog for the Duplicate Automation API."
  url="/changelog/duplicate-automation-api"
  image="https://cdn.resend.com/posts/duplicate-automation-api.jpg"
/>

### 6. Update Segment API

You could already create, retrieve, list, and delete segments from the API. The new update endpoint completes the set, so you can rename a segment from the API, CLI, or any official SDK.

<CodeTabs codeHeight={400}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.segments.update(
  '78261eea-8f8b-4381-83c6-79fa7120f1cf',
  {
    name: 'Active Users',
  },
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->segments->update('78261eea-8f8b-4381-83c6-79fa7120f1cf', [
  'name' => 'Active Users',
]);
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

params: resend.Segments.UpdateParams = {
  "name": "Active Users",
}

segment = resend.Segments.update("78261eea-8f8b-4381-83c6-79fa7120f1cf", params)
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

params = {
  segment_id: "78261eea-8f8b-4381-83c6-79fa7120f1cf",
  name: "Active Users"
}

Resend::Segments.update(params)
```

```go
import "github.com/resend/resend-go/v4"

client := resend.NewClient("re_xxxxxxxxx")

params := &resend.UpdateSegmentRequest{
  Name: "Active Users",
}

updated, _ := client.Segments.Update("78261eea-8f8b-4381-83c6-79fa7120f1cf", params)
```

```rust
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _segment = resend
    .segments
    .update("78261eea-8f8b-4381-83c6-79fa7120f1cf", "Active Users")
    .await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

UpdateSegmentOptions options = UpdateSegmentOptions.builder()
        .name("Active Users")
        .build();

UpdateSegmentResponseSuccess response = resend.segments().update("78261eea-8f8b-4381-83c6-79fa7120f1cf", options);
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var resp = await resend.SegmentUpdateAsync( new Guid( "78261eea-8f8b-4381-83c6-79fa7120f1cf" ), new SegmentData() {
  Name = "Active Users",
} );
```

```curl
curl -X PATCH 'https://api.resend.com/segments/78261eea-8f8b-4381-83c6-79fa7120f1cf' \
     -H 'Authorization: Bearer re_xxxxxxxxx' \
     -H 'Content-Type: application/json' \
     -d $'{
  "name": "Active Users"
}'
```

```cli
resend segments update 78261eea-8f8b-4381-83c6-79fa7120f1cf --name "Active Users"
```
</CodeTabs>

Learn more about the [Update Segment API](/docs/api-reference/segments/update-segment) or read the changelog.

<LinkCard
  title="Update Segment API Changelog"
  description="Read the full changelog for the Update Segment API."
  url="/changelog/update-segment-api"
  image="https://cdn.resend.com/posts/update-segment-api.jpg"
/>

### 7. List Clicked Links API

The List Clicked Links API returns every link clicked in a Broadcast with its total and unique clicks, ranked by total clicks. Use it to feed your own dashboards, compare CTAs across campaigns, or surface your top-performing links to inform future emails. Click tracking must be enabled for your domain.

<CodeTabs codeHeight={475}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.broadcasts.clickedLinks(
  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
  { limit: 20 },
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->broadcasts->clickedLinks->list('559ac32e-9ef5-46fb-82a1-b76b840c0f7b',[
  'limit' => 20
]);
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

resend.Broadcasts.clicked_links(
    id="559ac32e-9ef5-46fb-82a1-b76b840c0f7b",
    params={"limit": 20},
)
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

Resend::Broadcasts.clicked_links("559ac32e-9ef5-46fb-82a1-b76b840c0f7b", { limit: 20 })
```

```go
package main

import "github.com/resend/resend-go/v4"

func main() {
	client := resend.NewClient("re_xxxxxxxxx")

	client.Broadcasts.ClickedLinks("559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
}
```

```rust
use resend_rs::{Resend, Result, list_opts::ListOptions};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _links = resend
    .broadcasts
    .clicked_links("559ac32e-9ef5-46fb-82a1-b76b840c0f7b", ListOptions::default())
    .await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

ListBroadcastClickedLinksResponseSuccess data = resend.broadcasts().clickedLinks("559ac32e-9ef5-46fb-82a1-b76b840c0f7b");
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var resp = await resend.BroadcastClickedLinksAsync( new Guid( "559ac32e-9ef5-46fb-82a1-b76b840c0f7b" ) );
```

```curl
curl -X GET 'https://api.resend.com/broadcasts/559ac32e-9ef5-46fb-82a1-b76b840c0f7b/clicked-links?limit=20' \
     -H 'Authorization: Bearer re_xxxxxxxxx'
```

```cli
resend broadcasts clicked-links 559ac32e-9ef5-46fb-82a1-b76b840c0f7b --limit 20
```
</CodeTabs>

Learn more about the [List Clicked Links API](/docs/api-reference/broadcasts/list-broadcast-clicked-links) or read the changelog.

<LinkCard
  title="List Clicked Links API Changelog"
  description="Read the full changelog for the List Clicked Links API."
  url="/changelog/list-clicked-links-api"
  image="https://cdn.resend.com/posts/list-clicked-links.jpg"
/>

### 8. Update API Key Name

The Update API Key endpoint renames an API key in place. The token stays the same, and so do the key's permission and domain restriction, so you can keep key names in sync with a renamed project or clean up naming conventions from a script without rotating secrets.

<CodeTabs codeHeight={475}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.apiKeys.update(
  'b6d24b8e-af0b-4c3c-be0c-359bbd97381e',
  { name: 'Production' },
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->apiKeys->update('b6d24b8e-af0b-4c3c-be0c-359bbd97381e', [
  'name' => 'Production',
]);
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

params: resend.ApiKeys.UpdateParams = {
  "id": "b6d24b8e-af0b-4c3c-be0c-359bbd97381e",
  "name": "Production",
}

resend.ApiKeys.update(params)
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

params = {
  id: "b6d24b8e-af0b-4c3c-be0c-359bbd97381e",
  name: "Production"
}

Resend::ApiKeys.update(params)
```

```go
import "github.com/resend/resend-go/v4"

client := resend.NewClient("re_xxxxxxxxx")

params := &resend.UpdateApiKeyRequest{
  Name: "Production",
}

updated, _ := client.ApiKeys.Update("b6d24b8e-af0b-4c3c-be0c-359bbd97381e", params)
```

```rust
use resend_rs::types::UpdateApiKeyOptions;
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _api_key = resend
    .api_keys
    .update(
      "b6d24b8e-af0b-4c3c-be0c-359bbd97381e",
      UpdateApiKeyOptions::new("Production"),
    )
    .await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

UpdateApiKeyOptions params = UpdateApiKeyOptions.builder()
        .name("Production")
        .build();

UpdateApiKeyResponseSuccess apiKey = resend.apiKeys().update("b6d24b8e-af0b-4c3c-be0c-359bbd97381e", params);
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var resp = await resend.ApiKeyUpdateAsync(
    new Guid( "b6d24b8e-af0b-4c3c-be0c-359bbd97381e" ),
    "Production" );
```

```curl
curl -X PATCH 'https://api.resend.com/api-keys/b6d24b8e-af0b-4c3c-be0c-359bbd97381e' \
     -H 'Authorization: Bearer re_xxxxxxxxx' \
     -H 'Content-Type: application/json' \
     -d $'{
  "name": "Production"
}'
```

```cli
resend api-keys update b6d24b8e-af0b-4c3c-be0c-359bbd97381e --name "Production"
```
</CodeTabs>

Learn more about the [Update API Key Name endpoint](/docs/api-reference/api-keys/update-api-key) or read the changelog.

<LinkCard
  title="Update API Key Name Changelog"
  description="Read the full changelog for the Update API Key Name endpoint."
  url="/changelog/update-api-key-name"
  image="https://cdn.resend.com/posts/update-api-key-name.jpg"
/>

### 9. Duplicate Broadcast API

Most new Broadcasts start from one you've already sent. The new duplicate Broadcast endpoint creates a copy of any Broadcast, including ones that have already been sent. The copy keeps the segment, topic, sender, subject, reply-to, preview text, and content, and starts as a draft so nothing goes out until you review and send it.

To duplicate a Broadcast, use the Broadcast's ID with the duplicate endpoint.

<CodeTabs codeHeight={250}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, error } = await resend.broadcasts.duplicate(
  '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->broadcasts->duplicate('559ac32e-9ef5-46fb-82a1-b76b840c0f7b');
```

```python
import resend

resend.api_key = "re_xxxxxxxxx"

resend.Broadcasts.duplicate(id="559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

Resend::Broadcasts.duplicate("559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
```

```go
import "github.com/resend/resend-go/v4"

client := resend.NewClient("re_xxxxxxxxx")

duplicated, _ := client.Broadcasts.Duplicate("559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
```

```rust
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let _duplicated = resend
    .broadcasts
    .duplicate("559ac32e-9ef5-46fb-82a1-b76b840c0f7b")
    .await?;

  Ok(())
}
```

```java
Resend resend = new Resend("re_xxxxxxxxx");

DuplicateBroadcastResponseSuccess data = resend.broadcasts().duplicate("559ac32e-9ef5-46fb-82a1-b76b840c0f7b");
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var duplicated = await resend.BroadcastDuplicateAsync( new Guid( "559ac32e-9ef5-46fb-82a1-b76b840c0f7b" ) );
```

```curl
curl -X POST 'https://api.resend.com/broadcasts/559ac32e-9ef5-46fb-82a1-b76b840c0f7b/duplicate' \
     -H 'Authorization: Bearer re_xxxxxxxxx'
```

```cli
resend broadcasts duplicate 559ac32e-9ef5-46fb-82a1-b76b840c0f7b
```
</CodeTabs>

Learn more about the [Duplicate Broadcast API](/docs/api-reference/broadcasts/duplicate-broadcast) or read the changelog.

<LinkCard
  title="Duplicate Broadcast API Changelog"
  description="Read the full changelog for the Duplicate Broadcast API."
  url="/changelog/duplicate-broadcast-api"
  image="https://cdn.resend.com/posts/duplicate-broadcast-api.jpg"
/>

## Conclusion

Now that we've brought compatibility between all the different services, our next goal is to give you more precise control. 

For everything from API key provisioning to webhook filtering and scoping, we're working hard to make Resend the best experience for developers and agents.

In the meantime, you can start building today:

- [Connect the MCP server](/docs/mcp-server) and manage your Resend account from your agent
- [Install the CLI](/docs/cli) and run any of the commands above from your terminal
