REST examples against https://api.piisend.com/api/v1 in curl, JavaScript, and Python.
Call the Piisend REST API directly—each example has tabs for cURL, JavaScript (fetch), and Python (httpx). There is no installable SDK package. Delivery routing is handled on the server; your app only needs HTTPS and an API key.
Create an API key with the emails:send scope (and templates:write if you create templates via API). Keys are created from the dashboard under API → Keys.
Base URL: https://api.piisend.com/api/v1. Send JSON with Authorization: Bearer <YOUR_API_KEY> (pii_… prefix). For self-hosted deployments, point requests at your API host instead.
Authorization: Bearer <YOUR_API_KEY> Content-Type: application/json
Omit template_id; provide subject plus at least one of html or text. Works for transactional and marketing messages.
curl -sS -X POST "https://api.piisend.com/api/v1/emails" \
-H "Authorization: Bearer $PIISEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": ["alice@example.com"],
"subject": "Welcome to Example",
"html": "<h1>Hi Alice</h1><p>Thanks for signing up.</p>",
"text": "Hi Alice, thanks for signing up."
}'Use a dashboard template and pass template_vars. Do not send subject, html, or text in the same request as template_id.
curl -sS -X POST "https://api.piisend.com/api/v1/emails" \
-H "Authorization: Bearer $PIISEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": ["alice@example.com"],
"template_id": "YOUR_TEMPLATE_ID",
"template_vars": {
"firstName": "Alice",
"signupUrl": "https://app.example.com/welcome"
}
}'Pass Idempotency-Key so retries after network errors do not double-send the same OTP.
curl -sS -X POST "https://api.piisend.com/api/v1/emails" \
-H "Authorization: Bearer $PIISEND_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: otp:user@example.com:842913" \
-d '{
"to": ["user@example.com"],
"template_id": "YOUR_OTP_TEMPLATE_ID",
"template_vars": {
"name": "Rao",
"otp_code": "842913",
"expires_in": "10 minutes"
}
}'POST /templates creates a reusable template; use its id when sending.
curl -sS -X POST "https://api.piisend.com/api/v1/templates" \
-H "Authorization: Bearer $PIISEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "otp-login",
"subject": "Your OTP code is {{otp_code}}",
"html_body": "<h1>Hi {{name}}</h1><p>Your OTP is <b>{{otp_code}}</b></p>",
"text_body": "Hi {{name}}, your OTP is {{otp_code}}."
}'Non-2xx responses return JSON with a detail field when available.
# HTTP 4xx/5xx — body is JSON, e.g. {"detail":"..."}
curl -i -X POST "https://api.piisend.com/api/v1/emails" ...If you omit from_ (or have no verified domain yet), Piisend sends from the shared platform domain (see your dashboard for the exact address). After DNS verification, set from_ to your verified sender and optionally domain_id when sending.
POST /emails — send transactional, marketing, or templated mailGET /emails — list sent or scheduled mailPOST /templates — create reusable templatesGET /templates — list templates for your workspaceDocumentation
Quickstart, API reference, and webhooks—everything you need to send from your app.