noxtemp/api
Get an API key
DEVELOPER DOCS

The email is temporary. The API isn't.

Connect any app or script to NoxTemp to spin up disposable email addresses, poll the inbox, and read messages — one key, one clear rate limit.

TO / TEMP ADDRESS
NOXTEMP
StatusActive
Key limit60 req / hour
EndpointPOST /api/index.php
Session expires in (example) 29:59

Three things and you're calling the API

Every request hits the same endpoint — only the action value changes.

BASE URL
https://noxtemp.xyz/api/index.php
METHOD
POST (x-www-form-urlencoded)
AUTH HEADER
X-API-Key: tm_xxxxxxxx…
curl -X POST https://noxtemp.xyz/api/index.php \
  -H "X-API-Key: tm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -d "action=generate"
Always send the header, always use POST. Every action below (except the internal webhook actions) requires X-API-Key — there is no anonymous access for external apps. For scripts and servers, stick to POST with the header.
No session, no cookie. Actions like inbox, read, extend, delete and status normally pick up the address from the browser session. Calling them with an API key, you must pass email explicitly every time — there's no session to fall back on.

Endpoints

Every response is JSON and always includes ok: true/false. All endpoints below require an X-API-Key header and count against that key's rate limit. Most failures (invalid input, expired address, not found…) still return HTTP 200 with ok: false — see the Errors section for which status codes are used instead.

A few actions exist in the backend purely for our own infrastructure — receive and link_telegram are Postfix/Telegram-bot webhooks secured by a server-side secret, and the account-dashboard actions (Google login, key management) are used only by our own login page. None of these are meant for third-party integrations, so they're intentionally left out of this reference.

Rate Limiting

Every response to a request with an API key includes headers showing your remaining quota.

Illustration only — not your live usage. A 60/hour key, 42 requests used:
042 / 60 used60
429 once you exceed the limit — wait until reset_at, don't retry immediately.

Ready-made client — six languages

Copy the class, drop in your key, and start calling any endpoint.

NoxTempClient.php
// requires the php-curl extension (enabled by default on most installs)

class NoxTempClient
{
    private string $baseUrl;
    private ?string $apiKey;

    public function __construct(string $apiKey = null, string $baseUrl = 'https://noxtemp.xyz/api/index.php')
    {
        $this->apiKey  = $apiKey;
        $this->baseUrl = $baseUrl;
    }

    private function call(string $action, array $params = []): array
    {
        $params['action'] = $action;

        $ch = curl_init($this->baseUrl);
        $headers = ['Content-Type: application/x-www-form-urlencoded'];
        if ($this->apiKey) {
            $headers[] = 'X-API-Key: ' . $this->apiKey;
        }

        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query($params),
            CURLOPT_HTTPHEADER     => $headers,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 10,
        ]);

        $res  = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($code === 429) {
            throw new RuntimeException('Rate limit exceeded, try again later.');
        }

        return json_decode($res, true) ?: [];
    }

    public function generate(): array { return $this->call('generate'); }
    public function inbox(string $email): array { return $this->call('inbox', ['email' => $email]); }
    public function read(string $email, string $id): array { return $this->call('read', ['email' => $email, 'id' => $id]); }
}

// usage
$client = new NoxTempClient('tm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
$acc = $client->generate();
echo $acc['email'];
NoxTempClient.js
class NoxTempClient {
  constructor(apiKey = null, baseUrl = 'https://noxtemp.xyz/api/index.php') {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
  }

  async call(action, params = {}) {
    const body = new URLSearchParams({ action, ...params });
    const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
    if (this.apiKey) headers['X-API-Key'] = this.apiKey;

    const res = await fetch(this.baseUrl, { method: 'POST', headers, body });

    if (res.status === 429) {
      throw new Error('Rate limit exceeded, try again later.');
    }
    return res.json();
  }

  generate()            { return this.call('generate'); }
  inbox(email)         { return this.call('inbox', { email }); }
  read(email, id)      { return this.call('read', { email, id }); }
}

// usage
const client = new NoxTempClient('tm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
const acc = await client.generate();
console.log(acc.email);
noxtemp_client.py
# pip install requests

import requests


class NoxTempClient:
    def __init__(self, api_key=None, base_url='https://noxtemp.xyz/api/index.php'):
        self.api_key = api_key
        self.base_url = base_url

    def _call(self, action, **params):
        params['action'] = action
        headers = {}
        if self.api_key:
            headers['X-API-Key'] = self.api_key

        res = requests.post(self.base_url, data=params, headers=headers, timeout=10)

        if res.status_code == 429:
            raise Exception('Rate limit exceeded, try again later.')

        return res.json()

    def generate(self):
        return self._call('generate')

    def inbox(self, email):
        return self._call('inbox', email=email)

    def read(self, email, id):
        return self._call('read', email=email, id=id)


# usage
client = NoxTempClient('tm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
acc = client.generate()
print(acc['email'])
noxtemp-client.js (Node.js)
// npm install axios

const axios = require('axios');

class NoxTempClient {
  constructor(apiKey = null, baseUrl = 'https://noxtemp.xyz/api/index.php') {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
  }

  async call(action, params = {}) {
    const body = new URLSearchParams({ action, ...params });
    const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
    if (this.apiKey) headers['X-API-Key'] = this.apiKey;

    try {
      const res = await axios.post(this.baseUrl, body.toString(), { headers });
      return res.data;
    } catch (err) {
      if (err.response && err.response.status === 429) {
        throw new Error('Rate limit exceeded, try again later.');
      }
      throw err;
    }
  }

  generate()       { return this.call('generate'); }
  inbox(email)    { return this.call('inbox', { email }); }
  read(email, id) { return this.call('read', { email, id }); }
}

module.exports = NoxTempClient;

// usage
const client = new NoxTempClient('tm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
client.generate().then(acc => console.log(acc.email));
noxtemp_client.go
// standard library only — no go get needed

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

type NoxTempClient struct {
	APIKey  string
	BaseURL string
}

func NewNoxTempClient(apiKey string) *NoxTempClient {
	return &NoxTempClient{APIKey: apiKey, BaseURL: "https://noxtemp.xyz/api/index.php"}
}

func (c *NoxTempClient) call(action string, params url.Values) (map[string]interface{}, error) {
	if params == nil {
		params = url.Values{}
	}
	params.Set("action", action)

	req, err := http.NewRequest("POST", c.BaseURL, strings.NewReader(params.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	if c.APIKey != "" {
		req.Header.Set("X-API-Key", c.APIKey)
	}

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.StatusCode == 429 {
		return nil, fmt.Errorf("rate limit exceeded, try again later")
	}

	var out map[string]interface{}
	json.NewDecoder(res.Body).Decode(&out)
	return out, nil
}

func (c *NoxTempClient) Generate() (map[string]interface{}, error) {
	return c.call("generate", nil)
}

func (c *NoxTempClient) Inbox(email string) (map[string]interface{}, error) {
	return c.call("inbox", url.Values{"email": {email}})
}

func (c *NoxTempClient) Read(email, id string) (map[string]interface{}, error) {
	return c.call("read", url.Values{"email": {email}, "id": {id}})
}

func main() {
	client := NewNoxTempClient("tm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
	acc, _ := client.Generate()
	fmt.Println(acc["email"])
}
nox_temp_client.rb
# standard library only — no gem install needed

require 'net/http'
require 'uri'
require 'json'

class NoxTempClient
  def initialize(api_key = nil, base_url = 'https://noxtemp.xyz/api/index.php')
    @api_key = api_key
    @base_url = base_url
  end

  def call(action, params = {})
    params[:action] = action
    uri = URI.parse(@base_url)

    req = Net::HTTP::Post.new(uri)
    req.set_form_data(params)
    req['X-API-Key'] = @api_key if @api_key

    res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }

    raise 'Rate limit exceeded, try again later.' if res.code.to_i == 429

    JSON.parse(res.body)
  end

  def generate
    call('generate')
  end

  def inbox(email)
    call('inbox', email: email)
  end

  def read(email, id)
    call('read', email: email, id: id)
  end
end

# usage
client = NoxTempClient.new('tm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
acc = client.generate
puts acc['email']

Common error messages

Nearly all of these come back as HTTP 200 with ok: false — check msg, not the status code, for these.

msgMeaning
Not foundThe email or message doesn't exist
Not logged inNo address resolved — pass email explicitly when calling with an API key
expiredThe email address has expired
telegram_ownedAddress is linked to a Telegram account, so it can't be extended/deleted this way
already_ownedAddress is already linked to a different Telegram account
دومين غير صالحThe domain in generate_custom doesn't match a valid domain format
Unknown actionThe action value isn't recognized

When the status code itself matters

Outside the cases below, expect HTTP 200 — even for logical failures — with the outcome in the JSON body.

StatusMeaning
200Request handled — check ok in the body for success/failure
204CORS preflight (OPTIONS) — no body
403Bad webhook secret on receive/link_telegram
429Rate limit exceeded for this key — wait for the window to reset, don't retry immediately

Before you ship to production

01

Store the key in an environment variable — never hardcode it in published code.

02

Use a separate key per app so a leak only requires revoking one, not all of them.

03

Back off on 429s with a delay — don't retry immediately in a loop.