Seluruh API dalam satu curl
Lupakan SDK sejenak. Setiap contoh di bawah mengirim hal yang sama: body JSON ke POST /v1/chat/completions dengan Bearer token. Jika Anda bisa mengirim itu, Anda selesai. Dapatkan kunci dari halaman pendaftaran (kredit uji coba tidak memerlukan detail pembayaran), ekspor sebagai API_KEY, dan jalankan ini pertama kali.
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
}'Balasan adalah objek bergaya OpenAI. Teks ada di choices[0].message.content, dan blok usage memberi tahu Anda biaya panggilan dalam token. Ada satu model, uncensored, sehingga bidang model tidak pernah berubah. Anda dapat mengonfirmasi hal ini dengan GET /v1/models.
curl https://api.unrestrictedaiapi.com/v1/models -H "Authorization: Bearer $API_KEY"Dua batas yang perlu Anda hafal sebelum menulis kode: jendela konteks adalah 100.000 token yang dibagi antara prompt dan completion, dan max_tokens bernilai 2048 kecuali Anda meningkatkannya (hingga 32.000). Jika output Anda terus berhenti di tengah kalimat, nilai default itu adalah penyebab utamanya.
Python dengan httpx
httpx memberi Anda klien sinkron dengan timeout yang wajar dan pasangan asinkron saat Anda membutuhkannya. Tetapkan timeout secara eksplisit. Generasi teks panjang bisa memakan waktu lama dan default lima detik akan memotongnya.
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() mengubah setiap 4xx atau 5xx menjadi eksepsi, yang baik untuk skrip. Untuk apa pun yang berjalan lama, bungkus panggilan tersebut sehingga dua status mendapat kesempatan lagi: 429 (Anda mencapai batas per kunci 300 permintaan per menit) dan 503 (upstream_busy, yang akan jelas dalam beberapa detik). Yang lain, termasuk 401, 402 dan 403, tidak akan memperbaiki dirinya sendiri saat dicoba lagi.
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."}]))Ganti httpx.post dengan httpx.AsyncClient().post di dalam async def dan Anda memiliki versi asinkron dengan payload yang sama.
JavaScript dengan fetch
Node 18 dan versi lebih baru menyertakan fetch, sehingga tidak ada yang perlu diinstal. Simpan file sebagai .mjs (atau atur "type": "module") agar await di scope top-level berfungsi. Browser memiliki API yang sama, tetapi jangan letakkan kunci di kode front-end. Proksikan panggilan melalui backend Anda sendiri.
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);Perhatikan urutan pemeriksaan. fetch hanya menolak pada kegagalan jaringan, sehingga 402 atau 403 tiba sebagai respons normal. Uji res.ok sendiri dan baca JSON kesalahan, yang selalu memiliki bentuk {"error":{"code":...,"message":...}}.
Go dengan net/http
Go membutuhkan beberapa baris lagi tetapi tanpa dependensi. Tentukan hanya bidang struktur yang Anda baca; encoding/json mengabaikan sisanya. Membaca body respons ke dalam byte sebelum memeriksa status memungkinkan Anda mencetak pesan kesalahan server saat terjadi kesalahan.
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)
}Untuk produksi, buat satu http.Client{Timeout: 60 * time.Second} dan gunakan kembali. Klien default tidak memiliki batas waktu sama sekali, itulah bagaimana permintaan yang macet menjadi goroutine yang macet.
PHP dengan cURL dan Ruby dengan Net::HTTP
Ekstensi cURL PHP sudah ada di sebagian besar host. Bangun body dengan json_encode, kembalikan transfer sebagai string, lalu baca status dengan curl_getinfo. Melewati pemeriksaan status adalah kesalahan klasik: body 402 diuraikan dengan baik sebagai JSON dan kode Anda kemudian gagal pada kunci choices yang hilang.
<?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";Pada host bersama dengan max_execution_time yang rendah, pertahankan max_tokens agar wajar atau pindahkan panggilan ke worker antrian.
Pustaka standar cukup di sini juga. ENV.fetch segera melempar jika variabel hilang, yang lebih baik daripada mengirim bearer token kosong dan men-debug 401 selama sepuluh menit.
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")Jika Anda kemudian pindah ke Rails, body yang sama berfungsi dari pekerjaan latar belakang. Jauhkan panggilan dari siklus permintaan; generasi lebih lambat daripada kueri database.
Kedua cuplikan mengirim tepat body permintaan yang sama seperti yang dikirim oleh cuplikan Python, itulah intinya: jika satu bahasa berfungsi dan bahasa lain tidak, bandingkan JSON-nya, bukan klien. Cetak body permintaan mentah sekali dan bandingkan byte demi byte. Sembilan dari sepuluh kali, penyebab utamanya adalah header Content-Type yang hilang atau nama model yang diketik dengan huruf kapital.
Streaming tanpa pustaka
Streaming adalah satu-satunya tempat di mana HTTP biasa meminta sedikit lebih banyak dari Anda. Dengan stream: true, server merespons dengan server-sent events: setiap baris dimulai dengan data: , membawa potongan JSON, dan stream berakhir dengan data: [DONE]. Potongan penggunaan akhir ditambahkan secara otomatis, sehingga Anda mendapatkan hitungan token bahkan saat streaming. Potongan ini tidak memiliki entri choices, itulah mengapa loop di bawah ini memeriksa sebelum melakukan pengindeksan.
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()Pola yang sama dapat diportkan secara langsung. Dalam JavaScript, baca res.body dengan reader dan pisahkan berdasarkan baris baru. Dalam Go, bungkus resp.Body dalam bufio.Scanner. Dalam Ruby, berikan blok ke http.request dan gunakan read_body. Dalam PHP, atur callback CURLOPT_WRITEFUNCTION. Logikanya tidak pernah berubah: hapus awalan, berhenti pada sentinel, uraikan JSON, cetak delta.
Tes asap lima menit dan pemeriksaan anggaran
Sebelum Anda membangun di atas cuplikan ini, lakukan pemeriksaan kepatuhan singkat. Pertama, panggil /v1/models dengan kunci Anda; 200 membuktikan kunci dan jalur jaringan. Kedua, kirim permintaan obrolan terkecil yang Anda bisa dengan max_tokens bernilai 20. Ketiga, pecahkan sesuatu secara disengaja, seperti token pembawa kosong, dan konfirmasi bahwa kode Anda menampilkan 401 dengan jelas alih-alih crash karena bidang yang hilang.
Kemudian lakukan aritmatika sekali agar tidak ada kejutan. Harga adalah $0,25 per juta token input dan $1,00 per juta token output. Sebagai asumsi untuk ilustrasi, katakan permintaan mengirim 600 token prompt dan menerima 400 token kembali. Itu adalah 600 x $0,25 / 1.000.000 = $0,00015 masuk, ditambah 400 x $1,00 / 1.000.000 = $0,0004 keluar, sekitar $0,00055 per panggilan. Kredit uji coba $0,50 akan mencakup sekitar 900 panggilan sebesar itu. Prompt asli Anda akan berbeda, jadi baca blok usage pada beberapa respons dan kalikan dari sana.
Kredit uji coba berlaku selama tujuh hari dan tidak memerlukan detail pembayaran, yang membuatnya cukup untuk menguji semua lima bahasa. Jika Anda ingin kasus penggunaan untuk dituju, panduan konten NSFW menunjukkan contoh lengkap. Ingat bahwa satu kunci milik satu akun; jika Anda membuatnya ulang, perbarui semua skrip sekaligus, karena kunci lama akan berhenti berfungsi segera.
Kesalahan yang terlihat sama di setiap bahasa
Karena API adalah HTTP biasa, penanganan kegagalan identik di bahasa mana pun yang Anda pilih. Hafalkan tabel ini dan Anda dapat mengimpor setiap cuplikan di atas.
| Status | Arti | Tindakan |
|---|---|---|
| 400 | Permintaan buruk, seperti prompt plus max_tokens melebihi 100k | Potong prompt atau turunkan max_tokens |
| 401 | Kunci hilang atau tidak valid | Periksa API_KEY; kunci yang dihasil ulang membunuh kunci lama secara instan |
| 402 | no_credit: saldo habis atau masa uji coba telah berakhir | Isi saldo prabayar |
| 403 | content_blocked | Jangan coba lagi; konten seksual yang melibatkan anak di bawah umur selalu diblokir |
| 429 | Lebih dari 300 permintaan per menit | Tunggu sebentar lalu coba lagi |
| 503 | upstream_busy | Coba lagi dalam beberapa detik |
Setelah hal dasar berfungsi, atur stream: true untuk output token per token dan baca baris per baris peristiwa yang dikirim server. Buat prompt yang lebih baik dengan panduan prompting, atau sambungkan panggilan yang sama ke platform obrolan menggunakan panduan bot. Tarif ada di halaman harga.