# 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.

Source: https://docs.pidgely.com/quickstart/

This guide sends a real email through Pidgely. You need an account (Pidgely is in [early access](https://pidgely.com/#waitlist)) 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](https://docs.pidgely.com/authentication/#domain-restricted-keys).

```bash
export PIDGELY_API_KEY=pdg_your_key_here
```

## 2. Add and verify your domain

Pidgely only sends from domains you have verified. Add yours in the dashboard, or with the API:

```js tab="Node.js"
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);
```

```python tab="Python"
import os
import pidgely

pidgely.api_key = os.environ["PIDGELY_API_KEY"]

result = pidgely.Domains.create({
    "name": "acme.com",
})
print(result)
```

```php tab="PHP"
<?php

require __DIR__ . '/vendor/autoload.php';

$pidgely = Pidgely::client(getenv('PIDGELY_API_KEY'));

$result = $pidgely->domains->create([
    'name' => 'acme.com',
]);
var_dump($result);
```

```go tab="Go"
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)
}
```

```ruby tab="Ruby"
require "pidgely"

Pidgely.api_key = ENV["PIDGELY_API_KEY"]

result = Pidgely::Domains.create({
  name: "acme.com"
})
puts result
```

```bash tab="cURL"
curl -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:

```js tab="Node.js"
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);
```

```python tab="Python"
import os
import pidgely

pidgely.api_key = os.environ["PIDGELY_API_KEY"]

result = pidgely.Domains.verify("0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51")
print(result)
```

```php tab="PHP"
<?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);
```

```go tab="Go"
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)
}
```

```ruby tab="Ruby"
require "pidgely"

Pidgely.api_key = ENV["PIDGELY_API_KEY"]

result = Pidgely::Domains.verify("0199d7f0-1c2b-7e4d-a5f6-0b9c8d7e6f51")
puts result
```

```bash tab="cURL"
curl -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](https://docs.pidgely.com/guides/domains/) explains each record and how to troubleshoot.

## 3. Install an SDK

Install the official Pidgely SDK for your language. The cURL tab needs nothing.

```bash tab="Node.js"
npm install pidgely
```

```bash tab="Python"
pip install pidgely
```

```bash tab="PHP"
# Guzzle is the suggested HTTP client; any PSR-18 client works
composer require pidgely/pidgely-php guzzlehttp/guzzle
```

```bash tab="Go"
go get github.com/pidgely/pidgely-go
```

```bash tab="Ruby"
gem install pidgely
```

```bash tab="cURL"
# nothing to install
```

> [!PREVIEW]
> The Go SDK is published (v0.1). The Node.js, Python, PHP and Ruby SDKs are in preview (0.1) and being published now: see [SDKs](https://docs.pidgely.com/sdks/) for links and status.

## 4. Send an email

Replace `acme.com` with your verified domain and `delivered@example.com` with an inbox you can check.

```js tab="Node.js"
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);
```

```python tab="Python"
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 tab="PHP"
<?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);
```

```go tab="Go"
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)
}
```

```ruby tab="Ruby"
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 email
```

```bash tab="cURL"
curl -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:

```json
{ "id": "0199d8a2-6f3c-7c51-9e2a-3b1f0c6d4e21" }
```

## 5. Check what happened

Retrieve the email to see its `last_event` (`queued`, `delivered`, `bounced`, …):

```js
const { data } = await pidgely.emails.get('0199d8a2-6f3c-7c51-9e2a-3b1f0c6d4e21');
console.log(data.last_event);
```

For production, don't poll: subscribe to [webhooks](https://docs.pidgely.com/guides/webhooks/) such as `email.delivered`, `email.bounced` and `email.complained`.

## Next steps

- [Sending email](https://docs.pidgely.com/guides/sending/): batch, scheduling, attachments, tags and headers.
- [Idempotency](https://docs.pidgely.com/idempotency/): retry sends safely with an `Idempotency-Key`.
- [Webhooks](https://docs.pidgely.com/guides/webhooks/): verify signatures and handle retries.
- [Migrate from Resend](https://docs.pidgely.com/guides/migrate-from-resend/): moving existing code over.
- [SMTP relay](https://docs.pidgely.com/guides/smtp/): send from frameworks that only speak SMTP.
