Get started
Quickstart
Create an API key, verify your domain and send your first email with Pidgely in about two minutes, with the official SDKs or cURL.
This guide sends a real email through Pidgely. You need an account (Pidgely is in early access) and access to the DNS of a domain you own.
1. Create an API key
Create a key in the dashboard. It looks like pdg_k3x7m2qa4bnp6c5d_xyy4u7c2… and is shown only once, so store it in your secret manager. For a first test a full_access key is simplest; in production, prefer a sending_access key restricted to one domain.
export PIDGELY_API_KEY=pdg_your_key_here2. Add and verify your domain
Pidgely only sends from domains you have verified. Add yours in the dashboard, or with the API:
import { Pidgely } from 'pidgely';
const pidgely = new Pidgely(process.env.PIDGELY_API_KEY);
const { data, error } = await pidgely.domains.create({
name: 'acme.com',
});
console.log(data ?? error);import os
import pidgely
pidgely.api_key = os.environ["PIDGELY_API_KEY"]
result = pidgely.Domains.create({
"name": "acme.com",
})
print(result)<?php
require __DIR__ . '/vendor/autoload.php';
$pidgely = Pidgely::client(getenv('PIDGELY_API_KEY'));
$result = $pidgely->domains->create([
'name' => 'acme.com',
]);
var_dump($result);package main
import (
"context"
"fmt"
"os"
"github.com/pidgely/pidgely-go"
)
func main() {
ctx := context.Background()
client := pidgely.NewClient(os.Getenv("PIDGELY_API_KEY"))
result, err := client.Domains.Create(ctx, &pidgely.CreateDomainRequest{
Name: "acme.com",
})
if err != nil {
panic(err)
}
fmt.Println(result)
}require "pidgely"
Pidgely.api_key = ENV["PIDGELY_API_KEY"]
result = Pidgely::Domains.create({
name: "acme.com"
})
puts resultcurl -X POST 'https://api.pidgely.com/domains' \
-H "Authorization: Bearer $PIDGELY_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"name": "acme.com"
}'The response lists the DNS records to publish: a DKIM TXT record, an MX and an SPF TXT record on bounces.acme.com (the return path), and an optional DMARC record. Add them at your DNS provider, then ask Pidgely to check:
import { Pidgely } from 'pidgely';
const pidgely = new Pidgely(process.env.PIDGELY_API_KEY);
const { data, error } = await pidgely.domains.verify('0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51');
console.log(data ?? error);import os
import pidgely
pidgely.api_key = os.environ["PIDGELY_API_KEY"]
result = pidgely.Domains.verify("0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51")
print(result)<?php
require __DIR__ . '/vendor/autoload.php';
$pidgely = Pidgely::client(getenv('PIDGELY_API_KEY'));
$result = $pidgely->domains->verify('0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51');
var_dump($result);package main
import (
"context"
"fmt"
"os"
"github.com/pidgely/pidgely-go"
)
func main() {
ctx := context.Background()
client := pidgely.NewClient(os.Getenv("PIDGELY_API_KEY"))
result, err := client.Domains.Verify(ctx, "0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51")
if err != nil {
panic(err)
}
fmt.Println(result)
}require "pidgely"
Pidgely.api_key = ENV["PIDGELY_API_KEY"]
result = Pidgely::Domains.verify("0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51")
puts resultcurl -X POST 'https://api.pidgely.com/domains/0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51/verify' \
-H "Authorization: Bearer $PIDGELY_API_KEY"New domains are also re-checked automatically every few minutes. Domains & DNS explains each record and how to troubleshoot.
3. Install an SDK
Install the official Pidgely SDK for your language. The cURL tab needs nothing.
npm install pidgelypip install pidgely# Guzzle is the suggested HTTP client; any PSR-18 client works
composer require pidgely/pidgely-php guzzlehttp/guzzlego get github.com/pidgely/pidgely-gogem install pidgely# nothing to install4. Send an email
Replace acme.com with your verified domain and delivered@example.com with an inbox you can check.
import { Pidgely } from 'pidgely';
const pidgely = new Pidgely(process.env.PIDGELY_API_KEY);
const { data, error } = await pidgely.emails.send({
from: 'Acme <onboarding@acme.com>',
to: ['delivered@example.com'],
subject: 'Hello from Pidgely',
html: '<p>It works! 🎉</p>',
});
console.log(data ?? error);import os
import pidgely
pidgely.api_key = os.environ["PIDGELY_API_KEY"]
email = pidgely.Emails.send({
"from": "Acme <onboarding@acme.com>",
"to": ["delivered@example.com"],
"subject": "Hello from Pidgely",
"html": "<p>It works! 🎉</p>",
})
print(email)<?php
require __DIR__ . '/vendor/autoload.php';
$pidgely = Pidgely::client(getenv('PIDGELY_API_KEY'));
$email = $pidgely->emails->send([
'from' => 'Acme <onboarding@acme.com>',
'to' => ['delivered@example.com'],
'subject' => 'Hello from Pidgely',
'html' => '<p>It works! 🎉</p>',
]);
var_dump($email);package main
import (
"context"
"fmt"
"os"
"github.com/pidgely/pidgely-go"
)
func main() {
ctx := context.Background()
client := pidgely.NewClient(os.Getenv("PIDGELY_API_KEY"))
sent, err := client.Emails.Send(ctx, &pidgely.SendEmailRequest{
From: "Acme <onboarding@acme.com>",
To: []string{"delivered@example.com"},
Subject: "Hello from Pidgely",
Html: "<p>It works! 🎉</p>",
})
if err != nil {
panic(err)
}
fmt.Println(sent)
}require "pidgely"
Pidgely.api_key = ENV["PIDGELY_API_KEY"]
email = Pidgely::Emails.send({
from: "Acme <onboarding@acme.com>",
to: ["delivered@example.com"],
subject: "Hello from Pidgely",
html: "<p>It works! 🎉</p>"
})
puts emailcurl -X POST https://api.pidgely.com/emails \
-H "Authorization: Bearer $PIDGELY_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"from": "Acme <onboarding@acme.com>",
"to": ["delivered@example.com"],
"subject": "Hello from Pidgely",
"html": "<p>It works! 🎉</p>"
}'The response contains the email id:
{ "id": "0199d8a2-6f3c-7c51-9e2a-3b1f0c6d4e21" }5. Check what happened
Retrieve the email to see its last_event (queued, delivered, bounced, …):
const { data } = await pidgely.emails.get('0199d8a2-6f3c-7c51-9e2a-3b1f0c6d4e21');
console.log(data.last_event);For production, don't poll: subscribe to webhooks such as email.delivered, email.bounced and email.complained.
Next steps
- Sending email: batch, scheduling, attachments, tags and headers.
- Idempotency: retry sends safely with an
Idempotency-Key. - Webhooks: verify signatures and handle retries.
- Migrate from Resend: moving existing code over.
- SMTP relay: send from frameworks that only speak SMTP.