Geliştiriciler
API olarak Euphona motoru
api.euphonaai.com/v1 üzerinde tek bir REST sözleşmesi. Canlı SSE ilerleme bildirimli asenkron işler, imzalı dosya aktarımı, önekli anahtarlar ve ücretsiz bir test modu: on iki aylık kendi destek süresi olan, birinci taraf bir ürün.
Anahtarlar Studio ayarlarında oluşturulur: eu_test_… anında ve ücretsiz; eu_live_… ise kayıtlı bir kart eklendikten sonra aynı ekrandan, ilk işinden itibaren ücretlendirilerek. Test modu sözleşmenin tamamını çalıştırır.
Her şey bir iş
curl -X POST https://api.euphonaai.com/v1/masters \
-H "Authorization: Bearer $EUPHONA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"file_id": "file_8Kd2mQTz3XaV7pLw"}'
HTTP/2 202
{
"id": "job_7Vd2mHs5Yq8Tz3Xa",
"object": "job",
"type": "mastering",
"status": "queued",
"stage": null,
"metering": {
"pool": "payg",
"charged_minutes": 0,
"test_mode": false
}
}Tasarım
Nasıl tasarlandı
Pazarlığa açık olmayan dört karar; çünkü her biri, ilk kesintisini atlatan bir entegrasyonla atlatamayan bir entegrasyon arasındaki fark.
Her şey bir iş
Ses API’den geçmez, etrafından dolaşır
Bu API bir yan ürün değil, ürünün kendisi
Belge, sözleşmenin kendisidir
Adım adım
Bir entegrasyonun yapısı
Bir dosya oluştur, baytları imzalı hedefe gönder, bir iş gönder ve SSE üzerinden bitişini izle. Dört adım; işleve göre değişen tek kısım üçüncüsü.
1. Dosyayı oluştur ve bir yükleme hedefi al
curl -X POST https://api.euphonaai.com/v1/files \
-H "Authorization: Bearer $EUPHONA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"filename":"take-07.wav","bytes":58210044,"content_type":"audio/wav"}'
{
"id": "file_8Kd2mQ...",
"object": "file",
"status": "awaiting_upload",
"upload": { "protocol": "...", "url": "https://files.euphonaai.com/...", "expires_at": "..." }
}2. Baytları bize değil, files. adresine gönder
# upload.protocol alanını oku, tek bir mekanizma varsayma. Devam ettirilebilir
# yükleme mekanizması, sözleşme içindeki bir uygulama tercihidir ve büyük
# bir sürüm değişikliği olmadan değişebilir; belgede değil de bir alanda
# olmasının nedeni tam olarak bu.3. İşi izle
curl -N https://api.euphonaai.com/v1/jobs/job_4Rb.../events \
-H "Authorization: Bearer $EUPHONA_API_KEY"
event: job.progress
data: {"status":"analyzing","stage":"analyze","progress":{"fraction":0.4}}
event: job.completed
data: {"status":"succeeded","result":{...},"metering":{"pool":"payg","charged_minutes":3.4}}4. Sonucu işin kendisiyle doğrula
curl https://api.euphonaai.com/v1/jobs/job_4Rb... \
-H "Authorization: Bearer $EUPHONA_API_KEY"
{"id":"job_4Rb...","status":"succeeded","result":{...},
"metering":{"pool":"payg","charged_minutes":3.4}}
# İş kaynağı, durum makinesinin güncel gerçeğidir: bir akış ne gösterdiyse
# ya da neyi kaçırdıysa, harekete geçmeden önce onu yeniden oku. Kopan bir
# SSE bağlantısı Last-Event-ID ile yeniden bağlanır ve hiçbir şey kaybetmez.Başvuru
Yüzey
Her işlevin paylaştığı platform yüzeyi. Her işlev tek bir oluşturma uç noktası ekler; döndürdüğü iş aşağıdaki her şeyden geçer: aynı yaşam döngüsü, aynı olaylar, aynı rapor.
| Yöntem | Yol | Ne yapar |
|---|---|---|
| POST | /v1/files | Bir dosya oluşturur ve imzalı, devam ettirilebilir bir yükleme hedefi döndürür. |
| GET | /v1/files/{id} | İçe alma durumu, ölçülen süre, örnekleme hızı, kanallar, format. |
| DELETE | /v1/files/{id} | Bir dosyayı ve ondan üretilenleri siler; bir iş onu hâlâ kullanırken reddedilir. |
| GET | /v1/files/{id}/download | İmzalı, süresi dolan bir indirme URL’si. |
| GET | /v1/jobs | Birleşik okuma yüzeyi, imleçle sayfalanır. |
| GET | /v1/jobs/{id} | Durum, aşama, ilerleme, ücretlendirme ve ölçülen rapor. |
| POST | /v1/jobs/{id}/cancel | İptal eder; işleme aşaması başlamadan önce ücret alınmaz. |
| POST | /v1/jobs/{id}/input | awaiting_input durumundaki bir işin sorduğunu yanıtlar ve işi devam ettirir. Ücretlendirilmez. |
| GET | /v1/jobs/{id}/events | İşin yaşam süresi boyunca sunucu tarafından gönderilen olaylar. |
| POST | /v1/projects | Dosyaları ve işleri gruplar; Track Graph adını verdiğimiz ortak analiz her proje için ayrıdır. |
| GET | /v1/projects/{id} | Dosya ve iş kimlikleriyle birlikte tek bir proje. |
| GET | /v1/usage | Kota durumu ve iki ücretlendirme havuzu. |
| GET | /v1/webhook-endpoints | Bu anahtarın modundaki webhook uç noktaların. |
| POST | /v1/webhook-endpoints | Bir https URL’si kaydet; hiçbir şey kaydedilmeden önce imzalı bir sınamayı yanıtlar. |
| GET | /v1/webhook-endpoints/{id} | Tek bir uç nokta. Sırrı bir daha asla gösterilmez. |
| PATCH | /v1/webhook-endpoints/{id} | Olaylarını, açıklamasını veya URL’sini değiştir; yeni bir URL yeniden doğrulanır. |
| DELETE | /v1/webhook-endpoints/{id} | Sil; ona teslim edilmemiş olaylar atılır. |
| POST | /v1/webhook-endpoints/{id}/rotate-secret | Yeni bir imzalama sırrı; eskisi bir geçiş süresi boyunca imzalamaya devam eder. |
| GET | /v1/events | Otuz günlük olaylar ve her teslimatın sonucu. |
| GET | /v1/events/{id} | Teslim edildiği haliyle tek bir olay ve teslimatları. |
Webhook’lar
Bir işin bittiğini öğren
Bir iş bittiğinde ya da yanıtını beklediğinde gelen imzalı bildirimler; böylece bir entegrasyonun akışı açık tutması ya da sürekli sorgulaması gerekmez.
- Olaylar
job.completed,job.failed,job.canceledvejob.awaiting_input. Her biri,dataalanı sorgulamanın döndürdüğü iş kaynağının tıpatıp aynısı olan bir olaydır.- Çalışma alanı olayları
- Saklanan bir yüklemeye kaldırılabileceği bir tarih verildiğinde
file.expiring,dataolarak dosyayla; bir kullanım havuzu sınırının %80’ine veya %100’üne ulaştığındausage.threshold. İkisi de her iki moddaki uç noktalara ulaşır; dosya başına bir kez ya da eşik ve dönem başına bir kez. - Kayıt
- Yeni anahtarlarda bulunmayan
webhooks:managekapsamına sahip bir anahtar gerekir. URL https kullanmalı ve yalnızca herkese açık adreslere çözümlenmelidir; ayrıca hiçbir şey kaydedilmeden önce imzalı bir sınamayı, onu geri döndüren bir 2xx yanıtıyla yanıtlamalıdır. Teslimatlar yalnızca IPv4 üzerinden gönderilir, bu yüzden ana makinenin bir IPv4 adresi olmalıdır. - Teslimat
- En az bir kez; bu yüzden tekrarları
Euphona-Event-Idile ayıkla. 10 saniye içinde 2xx dışında gelen her yanıt 24 saat boyunca üstel geri çekilmeyle yeniden denenir, ardından teslim edilemeyenlere alınır veGET /v1/eventsiçinde tutulur. Yönlendirmeler asla izlenmez ve sıra garanti edilmez: işle karşılaştırarak uzlaştır. - İmzalar
Euphona-Signature, bir zaman damgası ile zaman damgası, nokta ve ham gövde üzerinden uç noktanın sırrıyla anahtarlanmış bir HMAC-SHA256 taşır. Ayrıştırmadan önce doğrula, sabit sürede karşılaştır ve saatinden beş dakikadan fazla sapan bir zaman damgasını reddet.- Kaynak adresler
- Teslimatlar
65.21.69.162adreslerinden gönderilir. Güvenlik duvarın gelen trafiği filtreliyorsa bunlara izin ver ve imzayı yine de doğrula: bir isteğin geldiği adres, onu kimin gönderdiğini kanıtlamaz.
Bir teslimatı doğrulamak (Node.js)
import { createHmac, timingSafeEqual } from "node:crypto";
// Gövdeyi tam geldiği gibi ilet: ayrıştırılıp yeniden serileştirilmiş JSON,
// imzalanan mesaj değildir.
export function verifyEuphonaSignature(rawBody, header, secret, now = Date.now() / 1000) {
const parts = header.split(",").map((part) => part.trim().split("="));
const t = Number(parts.find(([key]) => key === "t")?.[1]);
const signatures = parts.filter(([key]) => key === "v1").map(([, value]) => value);
if (!Number.isFinite(t) || Math.abs(now - t) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((value) => {
const given = Buffer.from(value, "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
});
}İşletim
Gece üçte can yakan şeyler
Entegrasyonu yazmadan önce okumaya değer altı davranış: seni uykundan uyandırdıktan sonra değil.
- Anahtarlar
eu_live_…veeu_test_…; bir çalışma alanına aittir, oluşturulurken bir kez gösterilir ve depolamada hash olarak tutulur. En fazla otuz günlük bir örtüşme süresiyle değiştir; böylece anahtar değişimi bir kesintiye dönüşmez. Test anahtarları kendi aylık sınırları dahilinde ücretsizdir ve kendi zamanlama sınıflarında çalışır; master yerine önizleme döndürürler, böylece bir entegrasyon hiçbir şey satın almadan baştan sona kurulabilir.- Hatalar
- Her zaman RFC 9457
application/problem+json; kararlı, makine tarafından okunabilir bircode, insanlar için birdetailve istek kimliğiyle. Dallanmayı metne göre değil, her zamancodedeğerine göre yap: metin yerelleştirilir, kod ise bir sözleşmedir. - Idempotency
- Her POST isteğinde
Idempotency-Key. Aynı anahtar aynı gövdeyle, oluşturduğu kaynak var olduğu sürece özgün yanıtı yeniden döndürür; aynı anahtar farklı bir gövdeyle reddedilir. Bu yüzden zaman aşımından sonra yapılan bir yeniden deneme, ücretlendirileceğin ikinci bir iş başlatmak yerine özgün işi döndürür. - Sınırlar
- Standart
RateLimit-*başlıklarıyla anahtar başına kayan pencere; kullandıkça öde modelinde dakikada 60 istek, taahhütlü kullanım sözleşmesinde daha fazlası. Sınırlayıcı yalnızca istek sıklığını yönetir: iş hacmini kotan ve kuyruk belirler. - İki sayaç, asla tek değil
- API anahtarıyla gelen işler kullandıkça öde havuzundan sayılır; Studio oturumundan gelen işler plan dakikalarından düşer. Hiçbir havuz diğerini tüketemez ve
GET /v1/usageikisini de bildirir. Harcama limitleri varsayılan olarak açıktır. Depolama alanı iki değil, tek bir kotadır: anahtarla yüklenen dosyalar ve API işlerinin sonuçları, Studio’daki her şeyle birlikte çalışma alanının planındaki depolama kotasından sayılır, ücretsiz planda 2 GB, ve sığmayacak bir yükleme ya da işstorage_fullile reddedilir. - Request-Id
- Başarılı ya da başarısız, her yanıtta. Bir destek talebinde belirttiğinde uçtan uca izlenebilir: işe, her aşamaya, gerçekte ne olduysa oraya kadar.
code | title |
|---|---|
| unauthenticated | Kimlik doğrulama gerekli |
| invalid_ | Geçersiz API anahtarı |
| key_ | API anahtarı iptal edildi |
| insufficient_ | Yetersiz kapsam |
| email_ | E-posta doğrulaması gerekli |
| malformed_ | Hatalı biçimlendirilmiş istek |
| validation_ | İstek doğrulanamadı |
| unsupported_ | Desteklenmeyen medya türü |
| idempotency_ | Idempotency anahtarı farklı bir gövdeyle yeniden kullanıldı |
| not_ | Bulunamadı |
| job_ | İş iptal edilemez |
| job_ | İş girdi beklemiyor |
| file_ | Dosya hazır değil |
| file_ | Dosyanın süresi doldu |
| file_ | Dosya kullanımda |
| file_ | Dosya yasal nedenlerle kullanılamıyor |
| unsupported_ | Desteklenmeyen ses formatı |
| unsupported_ | Desteklenmeyen örnekleme hızı |
| unsupported_ | Desteklenmeyen kanal sayısı |
| file_ | Ses çok uzun |
| file_ | Ses çok kısa |
| file_ | Dosya çok büyük |
| corrupt_ | Sesin kodu çözülemedi |
| rate_ | İstek sınırı aşıldı |
| too_ | Çok fazla etkin iş |
| quota_ | Kota aşıldı |
| spend_ | Harcama limitine ulaşıldı |
| test_ | Test modu sınırına ulaşıldı |
| storage_ | Depolama alanı dolu |
| purchase_ | Satın alma gerekli |
| payment_ | Ödeme yöntemi gerekli |
| format_ | Format bu plana dahil değil |
| webhook_ | Webhook URL’si HTTPS olmalıdır |
| webhook_ | Webhook URL’sine herkese açık ağdan erişilebilmelidir |
| webhook_ | Webhook sahipliği doğrulanamadı |
| internal_ | Dahili hata |
| service_ | Hizmet kullanılamıyor |
| processing_ | İşlem başarısız oldu |
| capacity_ | Kapasite yok |
| capability_ | Geçici olarak duraklatıldı |
| workspace_ | Çalışma alanı askıya alındı |
| uploads_ | Yüklemeler duraklatıldı |
| reauthentication_ | Sen olduğunu onayla |
Ücretler
Ne kadar tutar
İşlenen dakika başına, işlev çarpanıyla çarpılarak aylık faturalandırılır. Abonelik gerekmez, bir API çalışma alanı ücretsiz planda olabilir. Test modu ücretsizdir.
- Ayın ilk 100 dakikası
- $0,35
- 1.000 dakikaya kadar
- $0,25
- 10.000 dakikaya kadar
- $0,15
- Bunun ötesi ya da taahhütlü kullanım
- Konuşalım