Addresses API

Complete reference for all address endpoints -- create, retrieve, list, delete, and email access.

All endpoints use the base URL https://api.oneshotemail.com/v1 and require Authorization: Bearer <api_key> unless noted otherwise.

Create an address

POST /addresses

Creates a new one-shot email address. The address can be in receive mode (wait for an incoming email) or send mode (send a single outgoing email).

Receive mode

Create an address that waits for one inbound email:

curl -X POST https://api.oneshotemail.com/v1/addresses \
  -H "Authorization: Bearer osm_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "ttl_seconds": 3600,
    "label": "signup-test",
    "mode": "receive"
  }'

Request body:

FieldTypeRequiredDefaultDescription
ttl_secondsintNo3600Seconds until the address auto-expires.
labelstringNonullLabel for filtering and bulk cleanup.
modestringNo"receive""receive" or "send".

Response: 201 Created

{
  "id": "abc123xyz789def456",
  "address": "abc123xyz789def456@in.oneshotemail.com",
  "mode": "receive",
  "status": "waiting",
  "expires_at": "2026-03-08T12:00:00Z",
  "label": "signup-test"
}

Send mode

Create an address and immediately send one email from it:

curl -X POST https://api.oneshotemail.com/v1/addresses \
  -H "Authorization: Bearer osm_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "send",
    "ttl_seconds": 300,
    "label": "invoice-test",
    "send": {
      "to": "intake@myapp.com",
      "subject": "Test invoice submission",
      "text_body": "Please process this invoice.",
      "html_body": "<html><body><p>Please process this invoice.</p></body></html>",
      "attachments": [
        {
          "filename": "invoice.pdf",
          "content_type": "application/pdf",
          "content_base64": "JVBERi0xLjQK..."
        }
      ]
    }
  }'

Send request body (nested under send):

FieldTypeRequiredDescription
tostringYesDestination email address.
subjectstringYesEmail subject line.
text_bodystringNoPlain text email body.
html_bodystringNoHTML email body.
attachmentsarrayNoList of attachment objects.
attachments[].filenamestringYesFilename for the attachment.
attachments[].content_typestringYesMIME type (e.g., application/pdf).
attachments[].content_base64stringYesBase64-encoded file content.

Response: 201 Created

{
  "id": "def456abc789xyz123",
  "address": "def456abc789xyz123@out.oneshotemail.com",
  "mode": "send",
  "status": "sent",
  "send_to": "intake@myapp.com",
  "expires_at": "2026-03-08T12:05:00Z",
  "label": "invoice-test"
}

Error responses

StatusCodeDescription
400VALIDATION_ERRORInvalid request body (bad TTL, missing fields, etc.)
401UNAUTHORIZEDMissing or invalid API key.
402QUOTA_EXCEEDEDMonthly allocation and credits exhausted.
429RATE_LIMITEDToo many requests.

Get an address

GET /addresses/{id}

Retrieve an address by ID, including its current status and email summary (if an email has been received).

curl https://api.oneshotemail.com/v1/addresses/abc123xyz789def456 \
  -H "Authorization: Bearer osm_live_your_key"

Response: 200 OK (waiting — no email yet)

{
  "id": "abc123xyz789def456",
  "address": "abc123xyz789def456@in.oneshotemail.com",
  "mode": "receive",
  "status": "waiting",
  "expires_at": "2026-03-08T12:00:00Z",
  "label": "signup-test",
  "email": null
}

Response: 200 OK (received)

{
  "id": "abc123xyz789def456",
  "address": "abc123xyz789def456@in.oneshotemail.com",
  "mode": "receive",
  "status": "received",
  "expires_at": "2026-03-08T12:00:00Z",
  "label": "signup-test",
  "email": {
    "from": "noreply@example.com",
    "subject": "Verify your account",
    "received_at": "2026-03-08T11:30:00Z",
    "size_bytes": 15234,
    "has_attachments": true,
    "attachment_count": 2
  }
}

Error responses

StatusCodeDescription
401UNAUTHORIZEDMissing or invalid API key.
404NOT_FOUNDAddress does not exist.
410EXPIREDAddress has expired and been deleted.

Get email content

GET /addresses/{id}/email

Retrieve the full parsed email for an address. Returns the text body, HTML body, headers, and attachment metadata.

curl https://api.oneshotemail.com/v1/addresses/abc123xyz789def456/email \
  -H "Authorization: Bearer osm_live_your_key"

Response: 200 OK

{
  "from": "noreply@example.com",
  "to": "abc123xyz789def456@in.oneshotemail.com",
  "subject": "Verify your account",
  "text_body": "Click the link below to verify your account:\nhttps://example.com/verify?token=abc123",
  "html_body": "<html><body><p>Click <a href=\"https://example.com/verify?token=abc123\">here</a> to verify your account.</p></body></html>",
  "headers": {
    "Message-ID": "<abc@example.com>",
    "Date": "Sat, 08 Mar 2026 11:30:00 +0000",
    "DKIM-Signature": "v=1; a=rsa-sha256; d=example.com; ...",
    "Received-SPF": "pass"
  },
  "received_at": "2026-03-08T11:30:00Z",
  "size_bytes": 15234,
  "attachments": [
    {
      "filename": "invoice.pdf",
      "content_type": "application/pdf",
      "size_bytes": 52400,
      "download_url": "/addresses/abc123xyz789def456/email/attachments/0"
    },
    {
      "filename": "receipt.png",
      "content_type": "image/png",
      "size_bytes": 8100,
      "download_url": "/addresses/abc123xyz789def456/email/attachments/1"
    }
  ]
}

Error responses

StatusCodeDescription
401UNAUTHORIZEDMissing or invalid API key.
404NOT_FOUNDNo email has arrived yet (address is waiting).
410EXPIREDAddress has expired.

Download attachment

GET /addresses/{id}/email/attachments/{index}

Download a specific attachment by its zero-based index. Returns the raw binary file with correct Content-Type and Content-Disposition headers.

curl -O -J https://api.oneshotemail.com/v1/addresses/abc123xyz789def456/email/attachments/0 \
  -H "Authorization: Bearer osm_live_your_key"

Response: 200 OK

Headers:

Content-Type: application/pdf
Content-Disposition: attachment; filename="invoice.pdf"
Content-Length: 52400

Body: raw binary file content.

Error responses

StatusCodeDescription
404NOT_FOUNDNo such attachment index.
410EXPIREDAddress has expired.

Get raw email

GET /addresses/{id}/email/raw

Retrieve the complete raw RFC 822 email source. Useful for debugging and inspecting DKIM, SPF, and DMARC headers.

curl https://api.oneshotemail.com/v1/addresses/abc123xyz789def456/email/raw \
  -H "Authorization: Bearer osm_live_your_key"

Response: 200 OK (text/plain)

Return-Path: <noreply@example.com>
Received: from mail-wr1-f42.google.com ...
DKIM-Signature: v=1; a=rsa-sha256; d=example.com; ...
From: noreply@example.com
To: abc123xyz789def456@in.oneshotemail.com
Subject: Verify your account
Date: Sat, 08 Mar 2026 11:30:00 +0000
Content-Type: multipart/mixed; boundary="----=_Part_123"

------=_Part_123
Content-Type: text/plain; charset="UTF-8"

Click the link below to verify your account:
https://example.com/verify?token=abc123
------=_Part_123--

List addresses

GET /addresses

List addresses belonging to the authenticated user, with optional filtering and pagination.

curl "https://api.oneshotemail.com/v1/addresses?status=waiting&label=ci-run-abc123&limit=10" \
  -H "Authorization: Bearer osm_live_your_key"

Query parameters:

ParameterTypeDefaultDescription
statusstring(all)Filter: waiting, received, expired, sent.
labelstring(all)Filter by exact label match.
modestring(all)Filter: receive or send.
limitint20Max results per page (1—100).
cursorstring(none)Pagination cursor from a previous response.

Response: 200 OK

{
  "items": [
    {
      "id": "abc123xyz789def456",
      "address": "abc123xyz789def456@in.oneshotemail.com",
      "mode": "receive",
      "status": "waiting",
      "expires_at": "2026-03-08T12:00:00Z",
      "label": "ci-run-abc123",
      "email": null
    },
    {
      "id": "ghi789jkl012mno345",
      "address": "ghi789jkl012mno345@in.oneshotemail.com",
      "mode": "receive",
      "status": "received",
      "expires_at": "2026-03-08T12:00:00Z",
      "label": "ci-run-abc123",
      "email": {
        "from": "noreply@example.com",
        "subject": "Welcome!",
        "received_at": "2026-03-08T11:32:00Z",
        "size_bytes": 3200,
        "has_attachments": false,
        "attachment_count": 0
      }
    }
  ],
  "next_cursor": "eyJsYXN0X2tleSI6Ii4uLiJ9"
}

To fetch the next page, include the next_cursor value:

curl "https://api.oneshotemail.com/v1/addresses?cursor=eyJsYXN0X2tleSI6Ii4uLiJ9" \
  -H "Authorization: Bearer osm_live_your_key"

When next_cursor is null, there are no more results.


Delete an address

DELETE /addresses/{id}

Delete a specific address and all associated email data immediately, regardless of remaining TTL. Useful for test cleanup.

curl -X DELETE https://api.oneshotemail.com/v1/addresses/abc123xyz789def456 \
  -H "Authorization: Bearer osm_live_your_key"

Response: 204 No Content

No response body.


Bulk delete by label

DELETE /addresses?label={label}

Delete all addresses matching the given label. This is the recommended cleanup method for test suites.

curl -X DELETE "https://api.oneshotemail.com/v1/addresses?label=ci-run-abc123" \
  -H "Authorization: Bearer osm_live_your_key"

Response: 204 No Content

No response body. All matching addresses and their email data are permanently deleted.


Common patterns

Polling for an email

If you are not using an SDK with built-in wait_for_email(), you can poll the address endpoint:

# Create the address
ADDR=$(curl -s -X POST https://api.oneshotemail.com/v1/addresses \
  -H "Authorization: Bearer $ONESHOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ttl_seconds": 300}' | jq -r '.id')

# Poll until received
while true; do
  STATUS=$(curl -s https://api.oneshotemail.com/v1/addresses/$ADDR \
    -H "Authorization: Bearer $ONESHOT_API_KEY" | jq -r '.status')
  if [ "$STATUS" = "received" ]; then
    break
  fi
  sleep 2
done

# Fetch the email
curl -s https://api.oneshotemail.com/v1/addresses/$ADDR/email \
  -H "Authorization: Bearer $ONESHOT_API_KEY" | jq .

However, the SDKs handle polling for you with exponential backoff. Use wait_for_email() whenever possible.