package main
import (
"context"
"fmt"
"log"
"os"
"github.com/AhaSend/ahasend-go"
"github.com/AhaSend/ahasend-go/api"
"github.com/AhaSend/ahasend-go/models/requests"
"github.com/google/uuid"
)
func main() {
client := api.NewAPIClient(api.WithAPIKey(os.Getenv("AHASEND_API_KEY")))
accountID := uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID"))
ctx := context.Background()
webhookID := uuid.MustParse("c5a32c40-b351-439f-8230-779daed3e42c")
response, _, err := client.WebhooksAPI.UpdateWebhook(ctx, accountID, webhookID, requests.UpdateWebhookRequest{
Name: ahasend.String("Failures"),
URL: ahasend.String("https://example.com/webhook"),
Enabled: ahasend.Bool(true),
OnBounced: ahasend.Bool(true),
})
if err != nil {
log.Fatalf("Error updating webhook: %v", err)
}
fmt.Printf("Updated webhook %s\n", response.ID)
}
import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
const webhookId = "00000000-0000-4000-8000-000000000007";
const webhook = await client.webhooks.update(webhookId, {
name: "Transactional delivery events",
});
console.log("Webhook updated.", { id: webhook.id, name: webhook.name });
curl --request PUT \
--url https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"url": "<string>",
"enabled": true,
"on_reception": true,
"on_delivered": true,
"on_transient_error": true,
"on_failed": true,
"on_bounced": true,
"on_suppressed": true,
"on_opened": true,
"on_clicked": true,
"on_unsubscribed": true,
"on_complained": true,
"on_suppression_created": true,
"on_suppression_deleted": true,
"on_dns_error": true,
"on_contact_created": true,
"on_contact_updated": true,
"on_contact_deleted": true,
"on_contact_added_to_list": true,
"on_contact_removed_from_list": true,
"on_contact_subscribed": true,
"on_contact_unsubscribed": true,
"on_contact_complained": true,
"origins": [],
"domains": [
"<string>"
]
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}"
payload = {
"name": "<string>",
"url": "<string>",
"enabled": True,
"on_reception": True,
"on_delivered": True,
"on_transient_error": True,
"on_failed": True,
"on_bounced": True,
"on_suppressed": True,
"on_opened": True,
"on_clicked": True,
"on_unsubscribed": True,
"on_complained": True,
"on_suppression_created": True,
"on_suppression_deleted": True,
"on_dns_error": True,
"on_contact_created": True,
"on_contact_updated": True,
"on_contact_deleted": True,
"on_contact_added_to_list": True,
"on_contact_removed_from_list": True,
"on_contact_subscribed": True,
"on_contact_unsubscribed": True,
"on_contact_complained": True,
"origins": [],
"domains": ["<string>"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'url' => '<string>',
'enabled' => true,
'on_reception' => true,
'on_delivered' => true,
'on_transient_error' => true,
'on_failed' => true,
'on_bounced' => true,
'on_suppressed' => true,
'on_opened' => true,
'on_clicked' => true,
'on_unsubscribed' => true,
'on_complained' => true,
'on_suppression_created' => true,
'on_suppression_deleted' => true,
'on_dns_error' => true,
'on_contact_created' => true,
'on_contact_updated' => true,
'on_contact_deleted' => true,
'on_contact_added_to_list' => true,
'on_contact_removed_from_list' => true,
'on_contact_subscribed' => true,
'on_contact_unsubscribed' => true,
'on_contact_complained' => true,
'origins' => [
],
'domains' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.put("https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"enabled\": true,\n \"on_reception\": true,\n \"on_delivered\": true,\n \"on_transient_error\": true,\n \"on_failed\": true,\n \"on_bounced\": true,\n \"on_suppressed\": true,\n \"on_opened\": true,\n \"on_clicked\": true,\n \"on_unsubscribed\": true,\n \"on_complained\": true,\n \"on_suppression_created\": true,\n \"on_suppression_deleted\": true,\n \"on_dns_error\": true,\n \"on_contact_created\": true,\n \"on_contact_updated\": true,\n \"on_contact_deleted\": true,\n \"on_contact_added_to_list\": true,\n \"on_contact_removed_from_list\": true,\n \"on_contact_subscribed\": true,\n \"on_contact_unsubscribed\": true,\n \"on_contact_complained\": true,\n \"origins\": [],\n \"domains\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"enabled\": true,\n \"on_reception\": true,\n \"on_delivered\": true,\n \"on_transient_error\": true,\n \"on_failed\": true,\n \"on_bounced\": true,\n \"on_suppressed\": true,\n \"on_opened\": true,\n \"on_clicked\": true,\n \"on_unsubscribed\": true,\n \"on_complained\": true,\n \"on_suppression_created\": true,\n \"on_suppression_deleted\": true,\n \"on_dns_error\": true,\n \"on_contact_created\": true,\n \"on_contact_updated\": true,\n \"on_contact_deleted\": true,\n \"on_contact_added_to_list\": true,\n \"on_contact_removed_from_list\": true,\n \"on_contact_subscribed\": true,\n \"on_contact_unsubscribed\": true,\n \"on_contact_complained\": true,\n \"origins\": [],\n \"domains\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "webhook",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"url": "<string>",
"enabled": true,
"on_reception": true,
"on_delivered": true,
"on_transient_error": true,
"on_failed": true,
"on_bounced": true,
"on_suppressed": true,
"on_opened": true,
"on_clicked": true,
"on_unsubscribed": true,
"on_complained": true,
"on_suppression_created": true,
"on_suppression_deleted": true,
"on_dns_error": true,
"on_contact_created": true,
"on_contact_updated": true,
"on_contact_deleted": true,
"on_contact_added_to_list": true,
"on_contact_removed_from_list": true,
"on_contact_subscribed": true,
"on_contact_unsubscribed": true,
"on_contact_complained": true,
"origins": [
"recipient"
],
"scope": "global",
"domains": [
"<string>"
],
"success_count": 1,
"error_count": 1,
"errors_since_last_success": 1,
"last_request_at": "2023-11-07T05:31:56Z"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}Update a Webhook via the API
Update an AhaSend webhook with the API: change its URL, event types, enabled status or domain scope. Omitted fields stay unchanged; the secret can’t change.
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/AhaSend/ahasend-go"
"github.com/AhaSend/ahasend-go/api"
"github.com/AhaSend/ahasend-go/models/requests"
"github.com/google/uuid"
)
func main() {
client := api.NewAPIClient(api.WithAPIKey(os.Getenv("AHASEND_API_KEY")))
accountID := uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID"))
ctx := context.Background()
webhookID := uuid.MustParse("c5a32c40-b351-439f-8230-779daed3e42c")
response, _, err := client.WebhooksAPI.UpdateWebhook(ctx, accountID, webhookID, requests.UpdateWebhookRequest{
Name: ahasend.String("Failures"),
URL: ahasend.String("https://example.com/webhook"),
Enabled: ahasend.Bool(true),
OnBounced: ahasend.Bool(true),
})
if err != nil {
log.Fatalf("Error updating webhook: %v", err)
}
fmt.Printf("Updated webhook %s\n", response.ID)
}
import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
const webhookId = "00000000-0000-4000-8000-000000000007";
const webhook = await client.webhooks.update(webhookId, {
name: "Transactional delivery events",
});
console.log("Webhook updated.", { id: webhook.id, name: webhook.name });
curl --request PUT \
--url https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"url": "<string>",
"enabled": true,
"on_reception": true,
"on_delivered": true,
"on_transient_error": true,
"on_failed": true,
"on_bounced": true,
"on_suppressed": true,
"on_opened": true,
"on_clicked": true,
"on_unsubscribed": true,
"on_complained": true,
"on_suppression_created": true,
"on_suppression_deleted": true,
"on_dns_error": true,
"on_contact_created": true,
"on_contact_updated": true,
"on_contact_deleted": true,
"on_contact_added_to_list": true,
"on_contact_removed_from_list": true,
"on_contact_subscribed": true,
"on_contact_unsubscribed": true,
"on_contact_complained": true,
"origins": [],
"domains": [
"<string>"
]
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}"
payload = {
"name": "<string>",
"url": "<string>",
"enabled": True,
"on_reception": True,
"on_delivered": True,
"on_transient_error": True,
"on_failed": True,
"on_bounced": True,
"on_suppressed": True,
"on_opened": True,
"on_clicked": True,
"on_unsubscribed": True,
"on_complained": True,
"on_suppression_created": True,
"on_suppression_deleted": True,
"on_dns_error": True,
"on_contact_created": True,
"on_contact_updated": True,
"on_contact_deleted": True,
"on_contact_added_to_list": True,
"on_contact_removed_from_list": True,
"on_contact_subscribed": True,
"on_contact_unsubscribed": True,
"on_contact_complained": True,
"origins": [],
"domains": ["<string>"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'url' => '<string>',
'enabled' => true,
'on_reception' => true,
'on_delivered' => true,
'on_transient_error' => true,
'on_failed' => true,
'on_bounced' => true,
'on_suppressed' => true,
'on_opened' => true,
'on_clicked' => true,
'on_unsubscribed' => true,
'on_complained' => true,
'on_suppression_created' => true,
'on_suppression_deleted' => true,
'on_dns_error' => true,
'on_contact_created' => true,
'on_contact_updated' => true,
'on_contact_deleted' => true,
'on_contact_added_to_list' => true,
'on_contact_removed_from_list' => true,
'on_contact_subscribed' => true,
'on_contact_unsubscribed' => true,
'on_contact_complained' => true,
'origins' => [
],
'domains' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.put("https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"enabled\": true,\n \"on_reception\": true,\n \"on_delivered\": true,\n \"on_transient_error\": true,\n \"on_failed\": true,\n \"on_bounced\": true,\n \"on_suppressed\": true,\n \"on_opened\": true,\n \"on_clicked\": true,\n \"on_unsubscribed\": true,\n \"on_complained\": true,\n \"on_suppression_created\": true,\n \"on_suppression_deleted\": true,\n \"on_dns_error\": true,\n \"on_contact_created\": true,\n \"on_contact_updated\": true,\n \"on_contact_deleted\": true,\n \"on_contact_added_to_list\": true,\n \"on_contact_removed_from_list\": true,\n \"on_contact_subscribed\": true,\n \"on_contact_unsubscribed\": true,\n \"on_contact_complained\": true,\n \"origins\": [],\n \"domains\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/webhooks/{webhook_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"enabled\": true,\n \"on_reception\": true,\n \"on_delivered\": true,\n \"on_transient_error\": true,\n \"on_failed\": true,\n \"on_bounced\": true,\n \"on_suppressed\": true,\n \"on_opened\": true,\n \"on_clicked\": true,\n \"on_unsubscribed\": true,\n \"on_complained\": true,\n \"on_suppression_created\": true,\n \"on_suppression_deleted\": true,\n \"on_dns_error\": true,\n \"on_contact_created\": true,\n \"on_contact_updated\": true,\n \"on_contact_deleted\": true,\n \"on_contact_added_to_list\": true,\n \"on_contact_removed_from_list\": true,\n \"on_contact_subscribed\": true,\n \"on_contact_unsubscribed\": true,\n \"on_contact_complained\": true,\n \"origins\": [],\n \"domains\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "webhook",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"url": "<string>",
"enabled": true,
"on_reception": true,
"on_delivered": true,
"on_transient_error": true,
"on_failed": true,
"on_bounced": true,
"on_suppressed": true,
"on_opened": true,
"on_clicked": true,
"on_unsubscribed": true,
"on_complained": true,
"on_suppression_created": true,
"on_suppression_deleted": true,
"on_dns_error": true,
"on_contact_created": true,
"on_contact_updated": true,
"on_contact_deleted": true,
"on_contact_added_to_list": true,
"on_contact_removed_from_list": true,
"on_contact_subscribed": true,
"on_contact_unsubscribed": true,
"on_contact_complained": true,
"origins": [
"recipient"
],
"scope": "global",
"domains": [
"<string>"
],
"success_count": 1,
"error_count": 1,
"errors_since_last_success": 1,
"last_request_at": "2023-11-07T05:31:56Z"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}domains preserves associations, while [] clears the
associations of a resulting-scoped webhook. Moving from global to
scoped requires a non-empty domains array in the same request. Moving
to global clears associations and ignores supplied domains.
A domain-scoped key must be authorized for the existing webhook and
every newly supplied domain; changing to global requires
webhooks:write:all.
Turning on a contact event (the on_contact_* fields) for an account
without the marketing features returns HTTP 400. A webhook with any
contact event on needs an API key with contacts:read, and with
lists:read as well for on_contact_added_to_list,
on_contact_removed_from_list, on_contact_subscribed,
on_contact_unsubscribed, and on_contact_complained. This check runs
against the webhook as it will be after the update, so every update of
an enabled webhook that keeps a contact event on needs these scopes,
also an update of only name, url, scope, domains, or
origins, and returns HTTP 403 without them. A key without them can
only turn those events off or disable the webhook (enabled: false);
turning it on again needs the scopes. The marketing check runs first.
Note: The webhook secret is not updatable
Related Guides
- API authentication, Permission scopes, Webhook setup.
- Event reference, Webhook CLI, Local webhook testing.
- Signature verification, Retry policy, API errors.
- API rate limits.
Authorizations
API key for authentication. Non-empty Security Requirement values are AhaSend API-key roles. Roles listed within one requirement object are jointly required; separate requirement objects are alternatives.
Body
Partial update. Omitted and null scalar fields leave their stored values
unchanged. Domain transition rules depend on the webhook's existing
scope and are described on domains.
Webhook name
255Webhook URL
Whether the webhook is enabled
Trigger on message reception
Trigger on message delivery
Trigger on transient errors
Trigger on permanent failures
Trigger on bounces
Trigger on suppressions
Trigger on opens
Trigger on clicks
Trigger on unsubscribes
Trigger on spam complaints
Trigger on suppression creation
Trigger on suppression deletion
Trigger on DNS errors
Trigger on contact creation
Trigger on contact updates
Trigger on contact deletion
Trigger when a contact is added to a list
Trigger when a contact is removed from a list
Trigger when a contact subscribes
Trigger when a contact unsubscribes
Trigger when a contact reports spam
The origins of the contact and suppression events that the webhook
gets. Omit it or send null to keep the stored value; send all
four origins to get every origin again. An empty array is refused
with HTTP 400. An array that holds all four origins is saved as
null, so that an origin added later reaches the webhook too.
1Who made a change that a contact or suppression event reports:
recipient for the contact or recipient, through an unsubscribe link,
a one-click unsubscribe, or a spam complaint; api for you, through
the AhaSend API; dashboard for you, through the AhaSend dashboard;
system for AhaSend, for example after a bounce, an expired message or
an email validation, or when AhaSend support makes the change.
recipient, api, dashboard, system Webhook scope. Omit or send null to keep the current scope.
global, scoped, null Omit or send null to leave domain associations unchanged. An array
replaces associations when the resulting scope is scoped; []
explicitly clears them. Changing a global webhook to scoped
requires a non-empty array in the same request and otherwise
returns HTTP 400. Changing to global clears all associations;
supplied domains are ignored when the resulting scope is global.
Response
Webhook updated successfully
Object type identifier
webhook Unique identifier for the webhook
When the webhook was created
When the webhook was last updated
Webhook name
Webhook URL
Whether the webhook is enabled
Trigger on message reception
Trigger on message delivery
Trigger on transient errors
Trigger on permanent failures
Trigger on bounces
Trigger on suppressions
Trigger on opens
Trigger on clicks
Trigger on unsubscribes
Trigger on spam complaints
Trigger on suppression creation
Trigger on suppression deletion
Trigger on DNS errors
Trigger on contact creation
Trigger on contact updates
Trigger on contact deletion
Trigger when a contact is added to a list
Trigger when a contact is removed from a list
Trigger when a contact subscribes
Trigger when a contact unsubscribes
Trigger when a contact reports spam
The origins of the contact and suppression events that the webhook
gets, or null for every origin. Message events and
domain.dns_error have no origin, and the webhook always gets them.
Who made a change that a contact or suppression event reports:
recipient for the contact or recipient, through an unsubscribe link,
a one-click unsubscribe, or a spam complaint; api for you, through
the AhaSend API; dashboard for you, through the AhaSend dashboard;
system for AhaSend, for example after a bounce, an expired message or
an email validation, or when AhaSend support makes the change.
recipient, api, dashboard, system Webhook scope
global, scoped Domains this webhook applies to. Always present; global webhooks return an empty array.
Number of successful calls
x >= 0Number of unsuccessful calls
x >= 0Number of consecutive failed calls. Reset to zero by the next successful call.
x >= 0When the webhook was last called

