NL ▾
https://api.unrestrictedaiapi.com/v1uncensored2026-10-06
API-sleutel aanvragen

Unrestricted AI API snelstart: Python, JavaScript, Go, PHP en Ruby

Je hebt geen SDK nodig om Unrestricted AI API te gebruiken. Het gebruikt standaard HTTP en JSON, dus elke taal met een HTTP-client werkt. Deze pagina geeft je één getest verzoek voor Python, JavaScript, Go, PHP en Ruby, plus de statuscodes om af te handelen en de retryregel die scripts stabiel houdt.

Bijgewerkt

Belangrijkste punten

  1. Eén endpoint, één model-id (ongecensureerd), één draagtoken: dezelfde request body werkt in elke taal.
  2. Stel expliciete timeouts in. Lange generaties duren langer dan de meeste standaard client-timeouts.
  3. Controleer de statuscode voordat je parseren start; de body van 402 en 403 is geldige JSON zonder choices array.
  4. Herhaal alleen 429 en 503, met een korte backoff.

De hele API in één curl

Verget de SDK even. Elk voorbeeld hieronder stuurt hetzelfde: een JSON body naar POST /v1/chat/completions met een draagtoken. Als je dat kunt, ben je klaar. Haal een sleutel van de aanmeldpagina (het gratis proeftegoed vereist geen betaalgegevens), exporteer het als API_KEY en voer dit eerst uit.

curl https://api.unrestrictedaiapi.com/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "uncensored",
    "messages": [{"role": "user", "content": "Write a two-line noir opening set in a laundromat."}],
    "max_tokens": 120
  }'

Het antwoord is een OpenAI-stijl object. De tekst staat bij choices[0].message.content, en een usage blok vertelt wat de aanroep kostte in tokens. Er is één model, uncensored, dus het model veld verandert nooit. Dit bevestig je met GET /v1/models.

curl https://api.unrestrictedaiapi.com/v1/models -H "Authorization: Bearer $API_KEY"

Twee limieten die je moet onthouden voordat je code schrijft: het contextvenster is 100.000 tokens, gedeeld tussen prompt en antwoord, en max_tokens staat standaard op 2048, tenzij je het verhoogt (tot 32.000). Als je output stopt in de zin, is deze standaardwaarde de boosdoener.

Python met httpx

httpx geeft je een synchronische client met verstandige time-outs en een async variant als je die nodig hebt. Stel de time-out expliciet in. Lange generaties kunnen even duren en de standaard van vijf seconden stopt ze.

import os
import httpx

resp = httpx.post(
    "https://api.unrestrictedaiapi.com/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={
        "model": "uncensored",
        "messages": [
            {"role": "system", "content": "You are a blunt, vivid fiction writer."},
            {"role": "user", "content": "Pitch a heist where the vault is a night market."},
        ],
        "temperature": 0.9,
        "max_tokens": 300,
    },
    timeout=60.0,
)
resp.raise_for_status()
print(resp.json()["choices"][0]["message"]["content"])

raise_for_status() zet elke 4xx of 5xx om in een uitzondering, wat prima is voor een script. Voor langlopende taken wrap je de aanroep zodat twee statuscodes een tweede kans krijgen: 429 (je raakt de limiet van 300 verzoeken per minuut per sleutel) en 503 (upstream_busy, wat binnen enkele seconden oplost). Alles anders, inclusief 401, 402 en 403, lost zichzelf niet op bij retry.

import os
import time
import httpx

def chat(messages, retries=3):
    for attempt in range(retries + 1):
        r = httpx.post(
            "https://api.unrestrictedaiapi.com/v1/chat/completions",
            headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
            json={"model": "uncensored", "messages": messages, "max_tokens": 400},
            timeout=60.0,
        )
        if r.status_code in (429, 503) and attempt < retries:
            time.sleep(2 ** attempt)
            continue
        r.raise_for_status()
        return r.json()["choices"][0]["message"]["content"]

print(chat([{"role": "user", "content": "Name five cursed objects found in a thrift store."}]))

Vervang httpx.post door httpx.AsyncClient().post binnen een async def en je hebt de async versie met dezelfde payload.

JavaScript met fetch

Node 18 en nieuwer leveren fetch, dus er is niets te installeren. Sla het bestand op als .mjs (of stel "type": "module" in) zodat top-level await werkt. Browsers hebben dezelfde API, maar zet de sleutel niet in frontend code. Proxy de aanroep via je eigen backend.

const res = await fetch("https://api.unrestrictedaiapi.com/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "uncensored",
    messages: [{ role: "user", content: "Describe a villain's morning routine in four bullets." }],
    max_tokens: 250,
  }),
});

if (!res.ok) {
  const err = await res.json().catch(() => ({}));
  throw new Error(`HTTP ${res.status}: ${err?.error?.message ?? "unknown error"}`);
}

const data = await res.json();
console.log(data.choices[0].message.content);

Let op de volgorde van controles. fetch faalt alleen bij netwerkfouten, dus een 402 of 403 komt binnen als normaal antwoord. Test res.ok zelf en lees de fout-JSON, die altijd de structuur {"error":{"code":...,"message":...}} heeft.

Go met net/http

Go vereist een paar regels meer maar geen afhankelijkheden. Definieer alleen de structvelden die je leest; encoding/json negeert de rest. Het lichaam in bytes lezen voordat je de status controleert, stelt je in staat het foutbericht van de server af te drukken als er iets misgaat.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

type reply struct {
	Choices []struct {
		Message struct {
			Content string `json:"content"`
		} `json:"message"`
	} `json:"choices"`
}

func main() {
	payload, _ := json.Marshal(map[string]any{
		"model": "uncensored",
		"messages": []map[string]string{
			{"role": "user", "content": "Give me a ghost story in exactly three sentences."},
		},
		"max_tokens": 200,
	})

	req, _ := http.NewRequest("POST", "https://api.unrestrictedaiapi.com/v1/chat/completions", bytes.NewReader(payload))
	req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
	req.Header.Set("Content-Type", "application/json")

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

	body, _ := io.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("HTTP %d: %s", resp.StatusCode, body))
	}

	var out reply
	if err := json.Unmarshal(body, &out); err != nil {
		panic(err)
	}
	fmt.Println(out.Choices[0].Message.Content)
}

Voor productie bouw je één http.Client{Timeout: 60 * time.Second} en hergebruik je deze. De standaard client heeft helemaal geen time-out, waardoor een vastgelopen verzoek een vastgelopen goroutine wordt.

PHP met cURL en Ruby met Net::HTTP

De cURL-extensie van PHP staat op de meeste hosts al. Bouw de request body met json_encode, retourneer de transfer als string en lees de status met curl_getinfo. De statuscontrole overslaan is de klassieke fout: een 402 body decodeert gelukkig als JSON en je code faalt dan op een ontbrekend choices veld.

<?php
$payload = json_encode([
    "model" => "uncensored",
    "messages" => [
        ["role" => "user", "content" => "Write a villanelle opening about a broken vending machine."],
    ],
    "max_tokens" => 200,
]);

$ch = curl_init("https://api.unrestrictedaiapi.com/v1/chat/completions");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 60,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => $payload,
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($body === false || $status !== 200) {
    fwrite(STDERR, "HTTP $status: $body\n");
    exit(1);
}

$data = json_decode($body, true);
echo $data["choices"][0]["message"]["content"], "\n";

Op een gedeelde host met een lage max_execution_time, houd max_tokens bescheiden of verplaats de aanroep naar een wachtrij-worker.

De standaard bibliotheek is hier ook genoeg. ENV.fetch gooit direct een fout als de variabele ontbreekt, wat beter is dan een leeg draagtoken sturen en tien minuten debuggen voor een 401.

require "net/http"
require "json"
require "uri"

uri = URI("https://api.unrestrictedaiapi.com/v1/chat/completions")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch('API_KEY')}"
req["Content-Type"] = "application/json"
req.body = JSON.generate(
  model: "uncensored",
  messages: [{ role: "user", content: "Invent a tavern rumor that sounds too specific to be fake." }],
  max_tokens: 200
)

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 60) { |http| http.request(req) }
abort("HTTP #{res.code}: #{res.body}") unless res.is_a?(Net::HTTPSuccess)

puts JSON.parse(res.body).dig("choices", 0, "message", "content")

Als je later naar Rails verhuist, werkt dezelfde body vanuit een achtergrondtaak. Houd de aanroep buiten de request cyclus; generaties zijn langzamer dan een database query.

Beide snippets sturen precies de body die de Python versie stuurt, wat het punt is: als één taal werkt en een andere niet, diff de JSON, niet de client. Print de raw request body één keer en vergelijk byte voor byte. Negen keer op de tien is de boosdoener een ontbrekende Content-Type header of een model name die met een hoofdletter is getypt.

Streaming zonder library

Streaming is de enige plek waar plain HTTP je iets meer werk vraagt. Met stream: true antwoordt de server met server-sent events: elke regel begint met data: , draagt een JSON chunk, en de stream eindigt met data: [DONE]. Een laatste usage chunk wordt automatisch toegevoegd, dus je krijgt token counts zelfs bij streaming. Die chunk heeft geen choices entries, waarom de loop hieronder checkt voordat hij indexeert.

import json
import os
import httpx

body = {
    "model": "uncensored",
    "messages": [{"role": "user", "content": "Tell a campfire story about a lighthouse keeper."}],
    "stream": True,
    "max_tokens": 400,
}
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

with httpx.stream("POST", "https://api.unrestrictedaiapi.com/v1/chat/completions",
                  headers=headers, json=body, timeout=60.0) as r:
    r.raise_for_status()
    for line in r.iter_lines():
        if not line.startswith("data: "):
            continue
        data = line[6:]
        if data == "[DONE]":
            break
        chunk = json.loads(data)
        if chunk.get("choices"):
            print(chunk["choices"][0]["delta"].get("content") or "", end="", flush=True)
print()

Hetzelfde patroon porteer je direct. In JavaScript, lees res.body met een reader en split op newlines. In Go, wrap resp.Body in een bufio.Scanner. In Ruby, geef een block door aan http.request en gebruik read_body. In PHP, stel een CURLOPT_WRITEFUNCTION callback in. De logica verandert nooit: strip de prefix, stop bij de sentinel, parse de JSON, print de delta.

Een vijf minuten smoke test en een budget check

Voordat je bovenop een van deze snippets bouwt, voer een snelle sanity pass uit. Roep eerst /v1/models aan met je sleutel; een 200 bewijst de sleutel en netwerk pad. Stuur ten tweede het kleinste chat verzoek dat je kunt met max_tokens ingesteld op 20. Breek ten derde iets opzettelijk, zoals een lege bearer token, en bevestig dat je code de 401 duidelijk toont in plaats van crashen op een ontbrekend veld.

Doe de rekenkunde dan één keer zodat niets je verrast. Prijzen zijn $0,25 per miljoen input tokens en $1,00 per miljoen output tokens. Als aanname voor illustratie: stel een verzoek stuurt 600 prompt tokens en ontvangt 400 tokens terug. Dat is 600 x $0,25 / 1.000.000 = $0,00015 in, plus 400 x $1,00 / 1.000.000 = $0,0004 uit, ongeveer $0,00055 per aanroep. Het gratis proeftegoed van $0,50 dekt ongeveer 900 aanroepen van deze grootte. Je echte prompts verschillen, dus lees het usage blok op een paar antwoorden en vermenigvuldig daar vanaf.

Het gratis proeftegoed duurt zeven dagen en vereist geen betaalgegevens, wat ruim voldoende is om alle vijf de talen te testen. Als je een use case wilt nastreven, toont de NSFW content guide een compleet voorbeeld. Onthoud dat één sleutel bij één account hoort; als je deze regeneert, update dan alle scripts tegelijk, omdat de oude sleutel direct stopt met werken.

Fouten die er in elke taal hetzelfde uitzien

Omdat de API standaard HTTP is, is de foutafhandeling identiek welke taal je ook kiest. Onthoud deze tabel en je kunt elke snippet hierboven porten.

StatusBetekenisActie
400Slecht verzoek, zoals prompt plus max_tokens boven de 100kKnip de prompt of verlaag max_tokens
401Ontbrekende of ongeldige sleutelControleer API_KEY; een vernieuwde sleutel maakt de oude direct ongeldig
402no_credit: saldo opgebruikt of proefperiode verlopenLaad het prepaid tegoed op
403content_blockedNiet opnieuw proberen; seksuele inhoud met minderjarigen wordt altijd geblokkeerd
429Meer dan 300 verzoeken per minuutWacht en probeer het opnieuw
503upstream_busyProbeer het opnieuw na een paar seconden

Zodra de basis werkt, stel je stream: true in voor token-voor-token output en lees de server-sent events regel voor regel. Schrijf betere prompts met de prompting guide, of koppel dezelfde aanroep aan een chatplatform met de bot walkthrough. Tarieven staan op de pricing page.

Vragen en antwoorden

Heb ik de OpenAI SDK nodig om deze API aan te roepen?

Nee. De voorbeelden hier gebruiken alleen de standaard HTTP-tools van elke taal. De OpenAI SDKs werken ook als je hun base URL wijzigt naar https://api.unrestrictedaiapi.com/v1.

Welke model id moet ik versturen?

Altijd "ongecensureerd". Er is één model, en GET /v1/models somt het op.

Waarom stopt mijn antwoord midden in een zin?

De standaard max_tokens is 2048. Verhoog dit per verzoek, tot 32.000, zolang prompt plus antwoord binnen het contextvenster van 100.000 tokens blijft.

Welke fouten moet mijn code opnieuw proberen?

Herhaal 429 (rate limit) en 503 (upstream_busy) na een korte vertraging. 400, 401, 402 en 403 vereisen een wijziging aan jouw kant, dus ze opnieuw proberen verspil je aanroepen.

Je sleutel is nog maar één formulier verwijderd

Maak een account aan, kopieer de sleutel, wijzig de base URL. Dat is de hele setup.

API-sleutel aanvragen