Faktur OpenAI Anda mungkin menunjukkan total pengeluaran $4.237 bulan lalu, tetapi tidak menjelaskan bahwa $3.100 berasal dari satu endpoint ringkasan yang lepas kontrol, $700 dari pelanggan yang hanya membayar $50/bulan, dan $437 dari fitur yang hampir tidak digunakan. Untuk mengambil keputusan harga, kapasitas, atau roadmap, Anda perlu atribusi biaya per fitur, rute, dan pelanggan.
Panduan ini menunjukkan cara membangun atribusi biaya API OpenAI yang bisa dipakai di produksi: beri tag setiap request dengan metadata, log penggunaan token dan biaya, agregasikan di data warehouse, pasang budget guardrail per key, lalu uji wrapper dengan Apidog sebelum rilis.
💡 Apidog memberi visibilitas tingkat request dan pengujian skenario untuk memverifikasi wrapper pelacakan biaya sebelum masuk produksi. Gunakan Apidog untuk memutar ulang request bertag, memvalidasi bentuk log, dan memastikan setiap panggilan membawa metadata yang dibutuhkan data warehouse Anda.
Ringkasan
Implementasi minimum:
- Bungkus semua panggilan OpenAI dengan satu wrapper.
- Wajibkan metadata:
feature,route,customer_id,environment. - Ambil
response.usagedari API OpenAI. - Hitung
cost_usdsaat event ditulis. - Kirim satu baris JSON per request ke pipeline log.
- Agregasikan di BigQuery, ClickHouse, Snowflake, atau Postgres.
- Pasang budget limit per project key di OpenAI.
- Uji wrapper dengan pengujian skenario Apidog.
Mengapa Dasbor Penagihan OpenAI Tidak Cukup
Dasbor billing OpenAI berguna untuk melihat total pengeluaran, rincian model, dan batas penggunaan. Namun, untuk produk yang memakai LLM di beberapa fitur, pelanggan, environment, atau background job, informasi itu tidak cukup.
Yang biasanya hilang:
-
Tidak ada atribusi fitur: Anda tidak tahu apakah biaya berasal dari
support-chat,summarization, atau job embedding. - Tidak ada atribusi pelanggan: sulit menghitung margin per pelanggan B2B.
- Tidak real-time: data usage bisa terlambat puluhan menit hingga beberapa jam.
- Tidak ada alert granular: Anda tidak bisa membuat alert seperti “endpoint chat melebihi $50/jam”.
- Project key hanya membantu sebagian: key per project memberi satu dimensi atribusi, tetapi bukan per fitur, rute, atau pelanggan.
Untuk referensi harga yang dipakai dalam perhitungan biaya, lihat rincian harga GPT-5.5. Untuk konteks billing API lain, lihat penagihan penggunaan GitHub Copilot untuk tim API. Dokumentasi OpenAI tersedia di referensi API OpenAI resmi.
Model Data Atribusi Biaya
Mulailah dari satu aturan: setiap request OpenAI harus menghasilkan satu event terstruktur.
Skema minimum:
| Kolom | Tipe | Contoh | Fungsi |
|---|---|---|---|
request_id |
uuid | 7a91... |
Idempotensi, deduplikasi, retry |
timestamp |
timestamptz | 2026-05-06T14:23:01Z |
Analisis time-series |
feature |
text | support-chat |
Fitur produk |
route |
text | /api/v1/chat/answer |
HTTP route atau background job |
customer_id |
text | cust_4291 |
Biaya per pelanggan |
environment |
text | prod |
Pisahkan prod, staging, dev |
model |
text | gpt-5.5 |
Tarif model |
prompt_tokens |
int | 15234 |
Token input |
completion_tokens |
int | 812 |
Token output |
reasoning_tokens |
int | 4500 |
Token reasoning, ditagih sebagai output |
cached_tokens |
int | 12000 |
Token prompt cache |
latency_ms |
int | 2341 |
Korelasi biaya dan latency |
cost_usd |
numeric | 0.045672 |
Biaya request |
prompt_cache_key |
text | system-v3 |
Analisis cache hit |
error_code |
text | 429 |
Retry dan error analysis |
Hitung biaya saat event ditulis, bukan saat query. Dengan begitu, data historis tetap mencerminkan tarif yang berlaku pada hari request terjadi.
PRICING = { # USD per 1 juta token, per Mei 2026
"gpt-5.5": {"input": 5.00, "cached": 2.50, "output": 30.00},
"gpt-5.5-pro": {"input": 30.00, "cached": 15.00, "output": 180.00},
"gpt-5.4": {"input": 2.50, "cached": 1.25, "output": 15.00},
"gpt-5.4-mini": {"input": 0.25, "cached": 0.125, "output": 2.00},
}
def compute_cost_usd(
model,
prompt_tokens,
cached_tokens,
completion_tokens,
reasoning_tokens
):
rates = PRICING[model]
uncached = max(0, prompt_tokens - cached_tokens)
input_cost = (uncached * rates["input"]) / 1_000_000
cache_cost = (cached_tokens * rates["cached"]) / 1_000_000
output_cost = (
(completion_tokens + reasoning_tokens) * rates["output"]
) / 1_000_000
return round(input_cost + cache_cost + output_cost, 6)
Token reasoning dikembalikan di:
usage.completion_tokens_details.reasoning_tokens
Namun, token ini ditagih dengan tarif output. Jangan hitung sebagai input.
Wrapper Python untuk Semua Request OpenAI
Jangan panggil SDK OpenAI langsung dari banyak tempat. Buat satu wrapper dan paksa semua fitur melewatinya.
import time
import uuid
import json
import logging
from openai import OpenAI
client = OpenAI()
logger = logging.getLogger("llm.cost")
def call_with_attribution(
*,
feature,
route,
customer_id,
environment,
model,
messages,
**openai_kwargs
):
request_id = str(uuid.uuid4())
started = time.time()
error_code = None
response = None
try:
response = client.chat.completions.create(
model=model,
messages=messages,
**openai_kwargs
)
return response
except Exception as e:
error_code = getattr(e, "code", "unknown_error")
raise
finally:
latency_ms = int((time.time() - started) * 1000)
usage = response.usage if response else None
prompt_tokens = getattr(usage, "prompt_tokens", 0)
completion_tokens = getattr(usage, "completion_tokens", 0)
cached_tokens = (
getattr(
getattr(usage, "prompt_tokens_details", None),
"cached_tokens",
0
) or 0
)
reasoning_tokens = (
getattr(
getattr(usage, "completion_tokens_details", None),
"reasoning_tokens",
0
) or 0
)
cost_usd = compute_cost_usd(
model=model,
prompt_tokens=prompt_tokens,
cached_tokens=cached_tokens,
completion_tokens=completion_tokens,
reasoning_tokens=reasoning_tokens,
)
logger.info(json.dumps({
"event": "openai.request",
"request_id": request_id,
"feature": feature,
"route": route,
"customer_id": customer_id,
"environment": environment,
"model": model,
"prompt_tokens": prompt_tokens,
"completion_tokens": completion_tokens,
"reasoning_tokens": reasoning_tokens,
"cached_tokens": cached_tokens,
"latency_ms": latency_ms,
"cost_usd": cost_usd,
"error_code": error_code,
}))
Contoh pemakaian:
response = call_with_attribution(
feature="support-chat",
route="/api/v1/chat/answer",
customer_id="cust_4291",
environment="prod",
model="gpt-5.5",
messages=[
{"role": "system", "content": "Anda adalah asisten support."},
{"role": "user", "content": "Bagaimana cara reset password?"},
],
)
Kirim log JSON tersebut ke pipeline yang sudah ada: Vector, Fluent Bit, Logstash, OTLP collector, Kafka, Pub/Sub, atau langsung ke data warehouse.
Implementasi Node.js
Pola yang sama berlaku di Node.js: wrapper menerima metadata, menjalankan request, membaca usage, menghitung biaya, lalu menulis event JSON.
import OpenAI from "openai";
import crypto from "node:crypto";
const client = new OpenAI();
const PRICING = {
"gpt-5.5": {
input: 5.0,
cached: 2.5,
output: 30.0,
},
};
function computeCostUsd({
model,
promptTokens,
cachedTokens,
completionTokens,
reasoningTokens,
}) {
const rates = PRICING[model];
const uncached = Math.max(0, promptTokens - cachedTokens);
const inputCost = (uncached * rates.input) / 1_000_000;
const cacheCost = (cachedTokens * rates.cached) / 1_000_000;
const outputCost =
((completionTokens + reasoningTokens) * rates.output) / 1_000_000;
return Number((inputCost + cacheCost + outputCost).toFixed(6));
}
export async function callWithAttribution({
feature,
route,
customerId,
environment,
model,
messages,
...openaiArgs
}) {
if (!feature || !route || !customerId || !environment) {
throw new Error("Missing OpenAI attribution metadata");
}
const requestId = crypto.randomUUID();
const started = Date.now();
let response;
let errorCode = null;
try {
response = await client.chat.completions.create({
model,
messages,
...openaiArgs,
});
return response;
} catch (err) {
errorCode = err.code || "unknown_error";
throw err;
} finally {
const usage = response?.usage || {};
const promptTokens = usage.prompt_tokens || 0;
const completionTokens = usage.completion_tokens || 0;
const cachedTokens =
usage.prompt_tokens_details?.cached_tokens || 0;
const reasoningTokens =
usage.completion_tokens_details?.reasoning_tokens || 0;
const costUsd = computeCostUsd({
model,
promptTokens,
cachedTokens,
completionTokens,
reasoningTokens,
});
console.log(JSON.stringify({
event: "openai.request",
request_id: requestId,
feature,
route,
customer_id: customerId,
environment,
model,
prompt_tokens: promptTokens,
completion_tokens: completionTokens,
reasoning_tokens: reasoningTokens,
cached_tokens: cachedTokens,
latency_ms: Date.now() - started,
cost_usd: costUsd,
error_code: errorCode,
}));
}
}
Query Agregasi Biaya
Setelah event masuk ke data warehouse, mulai dari query harian per fitur:
SELECT
feature,
DATE_TRUNC(timestamp, DAY) AS day,
COUNT(*) AS requests,
SUM(cost_usd) AS spend_usd,
SUM(prompt_tokens + completion_tokens) AS tokens,
AVG(latency_ms) AS avg_latency_ms,
SUM(cached_tokens) / NULLIF(SUM(prompt_tokens), 0) AS cache_hit_rate
FROM openai_events
WHERE environment = 'prod'
AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
GROUP BY feature, day
ORDER BY day DESC, spend_usd DESC;
Query biaya per pelanggan:
SELECT
customer_id,
COUNT(*) AS requests,
SUM(cost_usd) AS spend_usd,
SUM(prompt_tokens) AS input_tokens,
SUM(completion_tokens + reasoning_tokens) AS output_tokens
FROM openai_events
WHERE environment = 'prod'
AND timestamp >= TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), MONTH)
GROUP BY customer_id
ORDER BY spend_usd DESC;
Query top route kemarin:
SELECT
route,
feature,
COUNT(*) AS requests,
SUM(cost_usd) AS spend_usd,
AVG(latency_ms) AS avg_latency_ms
FROM openai_events
WHERE environment = 'prod'
AND DATE(timestamp) = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)
GROUP BY route, feature
ORDER BY spend_usd DESC
LIMIT 20;
Dashboard minimum yang sebaiknya Anda punya:
- Pengeluaran per fitur dari waktu ke waktu.
- Pengeluaran per pelanggan dari waktu ke waktu.
- Top route berdasarkan biaya.
- Cache hit rate per fitur.
- Rata-rata prompt token per fitur.
- Error dan retry rate.
Uji Wrapper dengan Apidog
Wrapper atribusi biaya adalah bagian kritis dari sistem billing internal Anda. Jika metadata salah atau log tidak konsisten, dashboard akan terlihat benar tetapi angkanya salah.
Gunakan Apidog untuk menguji alur end-to-end:
- Buat skenario yang memanggil endpoint AI Anda.
- Kirim request dengan
customer_id,feature, dan payload yang diketahui. - Tangkap respons dan event log.
- Assert bahwa log memiliki:
featureroutecustomer_idenvironmentmodelprompt_tokens > 0cost_usd > 0
- Jalankan skenario di staging dan produksi memakai environment variable Apidog.
- Putar ulang request dan pastikan retry tidak menggandakan biaya.
Contoh assertion yang ingin Anda validasi:
{
"event": "openai.request",
"feature": "support-chat",
"route": "/api/v1/chat/answer",
"customer_id": "cust_test_001",
"environment": "staging",
"cost_usd": 0.001234
}
Untuk pendekatan pengujian API yang lebih luas, lihat alat pengujian API untuk insinyur QA. Jika Anda memakai pendekatan contract-first, lihat pengembangan API contract-first.
Pasang Budget Guardrail
Atribusi biaya memberi visibilitas. Guardrail mencegah kerusakan.
Gunakan project key OpenAI per environment atau per fitur:
prod-support-chatprod-summarizationprod-embeddingsstaging-alldev-all
Lalu:
- Tetapkan hard limit di dashboard OpenAI.
- Simpan key di secret manager.
- Map key ke service atau fitur tertentu.
- Tambahkan alert berbasis data warehouse.
Contoh alert SQL setiap 10 menit:
WITH hourly AS (
SELECT
feature,
TIMESTAMP_TRUNC(timestamp, HOUR) AS hour,
SUM(cost_usd) AS spend_usd
FROM openai_events
WHERE environment = 'prod'
AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 8 DAY)
GROUP BY feature, hour
),
baseline AS (
SELECT
feature,
AVG(spend_usd) AS avg_hourly_spend
FROM hourly
WHERE hour < TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)
GROUP BY feature
),
current_hour AS (
SELECT
feature,
SUM(cost_usd) AS current_spend
FROM openai_events
WHERE environment = 'prod'
AND timestamp >= TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), HOUR)
GROUP BY feature
)
SELECT
c.feature,
c.current_spend,
b.avg_hourly_spend
FROM current_hour c
JOIN baseline b USING (feature)
WHERE c.current_spend > b.avg_hourly_spend * 3;
Kirim hasilnya ke Slack, PagerDuty, Opsgenie, atau webhook internal.
Teknik Optimasi Biaya
1. Pakai prompt caching
GPT-5.5 mengenakan biaya lebih rendah untuk cached token. Strukturkan prompt agar bagian sistem stabil berada di awal, lalu variabel request di akhir.
Pantau:
SELECT
feature,
SUM(cached_tokens) / NULLIF(SUM(prompt_tokens), 0) AS cache_hit_rate
FROM openai_events
WHERE environment = 'prod'
GROUP BY feature
ORDER BY cache_hit_rate ASC;
Dokumentasi resmi: Prompt caching OpenAI.
2. Gunakan Batch API untuk workload offline
Pekerjaan seperti ringkasan malam, evaluasi, reprocessing dokumen, dan embedding backfill tidak perlu respons sinkron. Jalankan lewat Batch API jika cocok dengan kebutuhan workload Anda.
Tetap log event dengan metadata tambahan:
{
"feature": "nightly-summary",
"route": "batch:nightly-summary",
"batch_job_id": "batch_123"
}
3. Audit reasoning effort
Jika fitur memakai mode reasoning, cek apakah semua request benar-benar butuh effort tinggi.
Bandingkan:
- kualitas output
- latency
reasoning_tokenscost_usd
Untuk detail penggunaan API, lihat cara menggunakan API GPT-5.5.
4. Batasi ukuran context
Prompt panjang mahal. Jika prompt_tokens naik dari minggu ke minggu tanpa perubahan produk, kemungkinan prompt atau retrieval Anda membengkak.
Pantau:
SELECT
feature,
DATE_TRUNC(timestamp, WEEK) AS week,
AVG(prompt_tokens) AS avg_prompt_tokens
FROM openai_events
WHERE environment = 'prod'
GROUP BY feature, week
ORDER BY week DESC;
5. Tambahkan guard untuk request besar
Jika Anda tahu ada threshold token yang memicu biaya lebih tinggi, tambahkan warning di wrapper.
if prompt_tokens > 250_000:
logger.warning(json.dumps({
"event": "openai.large_prompt_warning",
"request_id": request_id,
"feature": feature,
"route": route,
"customer_id": customer_id,
"prompt_tokens": prompt_tokens,
}))
Untuk detail harga, lihat postingan harga GPT-5.5.
6. Batasi pengeluaran per pelanggan
Untuk SaaS B2B, tambahkan quota per customer_id.
Alur sederhana:
- Hitung spend bulanan per pelanggan.
- Simpan limit per plan.
- Sebelum request OpenAI, cek spend saat ini.
- Jika melewati limit, kembalikan
429.
Contoh respons:
{
"error": "ai_quota_exceeded",
"message": "Kuota AI bulanan terlampaui. Silakan upgrade paket atau hubungi admin billing."
}
Kesalahan Umum
Hindari ini:
- Menghitung reasoning token sebagai input. Reasoning token ditagih sebagai output.
- Mengandalkan dashboard OpenAI untuk alert real-time.
- Memberi tag di level SDK, bukan di call site.
- Melupakan background job, cron, queue worker, dan webhook.
- Sampling log. Untuk atribusi biaya, catat semua request.
- Membiarkan
customer_idbernilainull. - Tidak menduplikasi retry dengan
request_id. - Tidak menyimpan versi pricing saat menghitung
cost_usd.
Untuk route non-HTTP, gunakan nama sintetis:
cron:nightly-summarize
queue:image-caption
webhook:incoming-ticket
batch:embedding-backfill
Alternatif dan Peralatan
| Pendekatan | Kelebihan | Biaya | Cocok Untuk |
|---|---|---|---|
| API penggunaan OpenAI | Bawaan, akurat untuk total usage | Gratis | Satu project, kebutuhan sederhana |
| Helicone | Proxy, dashboard, caching, biaya per user | Free tier; berbayar mulai $20/bln | Ingin dashboard cepat |
| Langfuse | Open source, trace + cost | Self-host gratis; cloud mulai $29/bln | Ingin observability LLM open source |
| LangSmith | Integrasi kuat dengan LangChain | Mulai $39/user/bln | Tim yang sudah memakai LangChain |
| Data warehouse kustom | Kontrol penuh, tanpa proxy | Waktu engineering | Workload besar dan dimensi khusus |
Trade-off:
- Proxy seperti Helicone menambah hop di jalur request.
- Self-hosted observability memberi kontrol, tetapi Anda harus mengoperasikannya.
- Data warehouse kustom paling fleksibel, tetapi Anda menulis query dan alert sendiri.
- API usage OpenAI cukup untuk rekonsiliasi, bukan atribusi produk granular.
Referensi tambahan:
- Panduan Helicone tentang pelacakan biaya LLM
- Dokumentasi Langfuse tentang model usage dan cost
- Platform API untuk arsitektur mikroserevisi
Studi Kasus
SaaS B2B dengan pengeluaran LLM per pelanggan
Sebuah perusahaan intelijen penjualan menghabiskan $80.000/bulan untuk OpenAI. Setelah atribusi per pelanggan, mereka menemukan 12% pelanggan menghasilkan 71% pengeluaran. Mereka lalu menerapkan tier pricing, soft quota untuk plan bawah, dan overage charge. Margin fitur AI naik dari 41% ke 73% dalam satu kuartal.
Alat developer internal
Sebuah organisasi engineering memberi akses asisten GPT-5.5 ke developer. Dengan tag per developer, platform engineering menemukan tiga developer menyumbang 50% pengeluaran internal. Dua menjalankan loop agen otomatis yang lupa dimatikan. Setelah dihentikan, perusahaan menghemat $1.800/bulan.
Estimasi biaya fitur baru
Tim produk ingin meluncurkan fitur ringkasan. Dengan data historis, mereka menghitung:
- rata-rata prompt token per request
- rata-rata output token
- request per active user
- active user estimate
Hasilnya: sekitar $0,04 per active user per hari, atau $1,20 per bulan. Tim pricing menetapkan harga $5/user/bulan karena unit economics terlihat jelas.
Checklist Implementasi
Gunakan checklist ini sebelum rilis:
- [ ] Semua panggilan OpenAI melewati wrapper.
- [ ]
feature,route,customer_id, danenvironmentwajib. - [ ]
response.usagedicatat. - [ ]
reasoning_tokensdihitung sebagai output. - [ ]
cost_usddihitung saat write. - [ ] Event JSON masuk ke pipeline log.
- [ ] Data tersedia di warehouse.
- [ ] Dashboard per fitur, rute, dan pelanggan tersedia.
- [ ] Alert anomali biaya aktif.
- [ ] Project key dipisah per environment atau fitur.
- [ ] Budget limit dipasang di dashboard OpenAI.
- [ ] Wrapper diuji dengan Apidog.
Kesimpulan
Dasbor billing OpenAI menjawab “berapa total yang saya bayar?”. Produk Anda membutuhkan jawaban yang lebih operasional: fitur mana, pelanggan mana, route mana, dan request mana yang menghasilkan biaya.
Bangun wrapper, catat metadata, hitung biaya saat write, agregasikan di data warehouse, lalu pasang alert dan budget guardrail.
Poin utama:
- Beri tag setiap request dengan fitur, route, pelanggan, dan environment.
- Hitung biaya saat event ditulis agar angka historis stabil.
- Gunakan project key per environment atau fitur sebagai guardrail.
- Tambahkan alert berbasis warehouse untuk mendeteksi lonjakan lebih cepat.
- Uji wrapper dengan Apidog sebelum produksi.
- Audit prompt, caching, dan reasoning effort secara berkala.
Unduh Apidog dan gunakan untuk memverifikasi wrapper atribusi biaya Anda: jalankan request bertag, validasi payload log, dan putar ulang skenario di semua environment.
Untuk bacaan terkait, lihat rincian harga GPT-5.5 dan penagihan penggunaan GitHub Copilot untuk tim API.
FAQ
Apakah token reasoning dihitung sebagai input atau output?
Output. OpenAI mengembalikannya di usage.completion_tokens_details.reasoning_tokens. Tambahkan ke completion_tokens saat menghitung biaya. Lihat rincian harga GPT-5.5.
Seberapa akurat response.usage dibandingkan dashboard OpenAI?
Jumlah token dari response.usage seharusnya cocok dengan usage yang ditagihkan. Selisih biaya biasanya terjadi jika tabel pricing internal Anda sudah usang.
Bisakah atribusi cukup dengan project key OpenAI?
Tidak untuk kebutuhan granular. Project key membantu membagi usage per project atau environment, tetapi tidak memberi atribusi per fitur, pelanggan, atau route.
Bagaimana dengan retry?
Request gagal sebelum model berjalan biasanya tidak memiliki usage, jadi tidak dicatat sebagai biaya. Jika request berhasil lalu aplikasi melakukan retry, Anda bisa mencatat biaya dua kali. Gunakan request_id yang sama untuk retry idempoten dan deduplikasi saat write.
Seberapa cepat API usage OpenAI mengembalikan data?
Biasanya ada jeda. Gunakan API usage untuk rekonsiliasi, bukan alert real-time. Untuk alert, gunakan event dari wrapper Anda sendiri.
Haruskah saya sampling request untuk mengurangi volume log?
Tidak. Satu baris JSON per request biasanya kecil. Sampling merusak atribusi per pelanggan dan per route.
Bisa dipakai untuk penyedia LLM lain?
Ya. Tambahkan kolom provider, misalnya:
openai
anthropic
google
deepseek
Lalu buat tabel pricing per provider. Untuk perbandingan, lihat harga API DeepSeek V4.
Apakah berlaku untuk embeddings dan image generation?
Ya, tetapi rumus biayanya berbeda. Tambahkan kolom endpoint:
chat
embeddings
image
Lalu cabangkan perhitungan biaya berdasarkan endpoint.
Top comments (0)