AeroNyx Sohbet Aktarıcısı İstemci Entegrasyonu

AeroNyx20 dk okuma

AeroNyx Sohbet Aktarıcısı için entegrasyon başvuru kaynağı: WebSocket kimlik doğrulaması, mühürlü birebir ve grup mesajları, çevrimdışı teslim, teslim ve okundu bilgileri, tepkiler, çevrimiçi durumu, şifrelenmiş ekler, anlık bildirimler ve hız sınırları.

Entegrasyon istemi oluştur

İstemci teknolojisini ve görevi seçip kodlama yardımcınıza kopyalayın. İstem yerel olarak oluşturulur; yapay zekâ hizmetine gönderilmez.

Oluşturulan istem

Bu belge, AeroNyx Sohbet Aktarıcısı (Chat Relay) için entegrasyon başvuru kaynağıdır: api.aeronyx.network adresindeki bu WebSocket ve HTTPS hizmeti, AeroNyx kimlikleri arasında uçtan uca şifrelenmiş birebir (1:1) mesajları, grup mesajlarını, teslim ve okundu bilgilerini, tepkileri, çevrimiçi durumunu ve şifrelenmiş ekleri taşır.

Belge, AeroNyx uyumlu istemciler, botlar ve hizmetler geliştiren mühendisler ile bunları uygulayan yapay zekâ kodlama ajanları için yazılmıştır. Bu sayfadaki her çerçeve, alan ve sınır, Ekim 2026 itibarıyla üretimdeki aktarıcıyı ve AeroNyx App'i yansıtır.

Sohbet Aktarıcısı merkezî teslim yoludur. Merkeziyetsiz düğüm yoluyla (onion yönlendirme ve anonim posta kutuları; bkz. "Doğrulanmış iki atlamalı teslim") birlikte çalışır; bir istemci her ikisini de kullanabilir. WebSocket kullanmayan, istek/yanıt tabanlı bir HTTPS entegrasyonu için Merkezî Sohbet HTTPS API v1 sayfasına bakın.

Güven modeli

Aktarıcı içeriğe kördür. İstemciler her şeyi aktarıcıya ulaşmadan önce şifreler ve imzalar; aktarıcı ise yalnızca opak şifreli metni yönlendirir, kuyruğa alır ve hız sınırı uygular.

Aktarıcı şunları hiçbir zaman almaz:

  • açık metin hâlinde mesaj metni, tepki emojisi, düzenlemeler veya grup yükleri
  • sohbet anahtarları, grup anahtarları, ek anahtarları veya nonce değerleri
  • ek içerikleri, dosya adları, küçük resimler, dalga formları veya dökümler
  • özel kimlik anahtarları

Aktarıcı ise teslim meta verilerini görür; entegrasyonu yapanlar bu verileri operatör tarafından görülebilir kabul etmelidir:

  • gönderici ve alıcı açık anahtarları, grup kimlikleri ve mesaj kimlikleri
  • zaman damgaları, yük boyutları ve teslim, alındı ve okundu durumu
  • çevrimiçi durumu, ön plan durumu ve yazıyor göstergeleri (açık metin çerçeveler olarak gönderilir)
  • arama sinyalleşmesi meta verileri (oda adı, arama kimliği, video bayrağı)
  • ekin şifreli metin boyutu, bildirilen medya türü ve sona erme zamanı
  • contact_request bayrağı ve IP düzeyindeki bağlantı meta verileri

İçeriğin gizliliği, aktarıcıdaki erişim denetiminden değil uçtan uca şifrelemeden gelir. Tasarımınızı buna göre yapın: depolanmış bir şifreli metni ele geçiren saldırgan yine de onu okuyamamalıdır.

Kimlikler ve anahtarlar

Bir AeroNyx sohbet kimliği, bir Ed25519 anahtar çiftidir. 64 küçük harfli onaltılık karakter olarak yazılan 32 baytlık açık anahtar, adrestir. Anahtarları cihazda üretin ve özel anahtarı hiçbir yere göndermeyin.

Bir kimlik çiftinden iki anahtar türetilir:

  • Sohbet anahtarı (1:1). HKDF-SHA256(salt = empty, ikm = X25519(my_secret, peer_public), info = "AERONYX-P2P-KEY", length = 32); burada her iki Ed25519 anahtarı da X25519'a dönüştürülür (gizli anahtar için SHA-512(seed)[0..32] kırpılarak (clamping), açık anahtar için Edwards'tan Montgomery'ye dönüşümle). İki taraf da aynı anahtarı türetir.
  • Mesaj imzaları. Bu sayfada tanımlanan bayt dizilerinin tam hâli üzerinde, kimlik anahtarıyla Ed25519.

Çerçevelerdeki açık anahtarlar için her zaman küçük harfli onaltılık gösterim kullanın. Aktarıcı her kuyruk anahtarında büyük/küçük harf normalleştirmesi yapmaz.

Kimlik doğrulama

RelayAuth imzası

WebSocket oturum açma işlemi ve kimlik doğrulaması gerektiren her HTTPS uç noktası aynı imzayı kullanır:

text
digest    = SHA256("AeroNyx-RelayAuth-v1" || pubkey[32] || timestamp as u64 little-endian)
signature = Ed25519(identity_key, digest)

"AeroNyx-RelayAuth-v1", sonlandırıcı içermeyen 20 ASCII bayttır. timestamp Unix saniyesi cinsindendir ve sunucu saatinden en fazla 300 saniye sapabilir.

İmza yalnızca kimliği ve zamanı bağlar. Yöntemi, yolu, gövdeyi veya bağlantıyı bağlamaz ve nonce içermez. Her istek için yeni bir zaman damgası üretin, imzayı yalnızca TLS üzerinden gönderin ve asla günlüğe kaydetmeyin.

HTTPS başlığı

http
Authorization: Relay <pubkey-hex>:<timestamp>:<signature-hex>

Başarısız bir denetim, {"success": false, "error": "<reason>"} ile birlikte HTTP 401 döndürür. Nedenler arasında missing_auth_header, malformed_auth_header, invalid_timestamp, timestamp_expired, invalid_pubkey ve invalid_signature bulunur.

WebSocket bağlantısı

Uç nokta

text
wss://api.aeronyx.network/ws/relay/

Yerel istemciler Origin başlığı olmadan bağlanır. Tarayıcılar izin verilen bir kaynaktan bağlanmalıdır; başka herhangi bir kaynak veya bilinmeyen bir Host söz konusu olduğunda bağlantı 1008 koduyla kapatılır.

Oturum açma

Sunucu soketi kabul eder, ardından 30 saniye içinde bir auth çerçevesi bekler:

json
{
  "type": "auth",
  "pubkey": "<64 hex>",
  "timestamp": 1780000000,
  "signature": "<128 hex>"
}

Başarılı yanıt:

json
{ "type": "auth_ack", "session_id": "<uuid>", "server_ts": 1780000001 }

Saat farkını tahmin etmek için server_ts değerini kullanın; mesaj zaman damgaları da aynı ±300 saniyelik pencereye göre denetlenir.

auth_ack sonrasında sunucu kalp atışını başlatır, bağlantıyı kanallarına abone eder ve çevrimdışı kuyruğu hemen yeniden oynatır (bkz. "Çevrimdışı teslim").

Başarısızlık durumunda {"type": "auth_error", "reason": "<reason>"} gönderilir ve soket 4001 koduyla kapatılır. Nedenler: missing_fields, timestamp_expired, invalid_pubkey, invalid_signature_length, invalid_signature_encoding, invalid_signature, internal_error. Oturum açma zaman aşımında timeout nedeni gönderilir ve bağlantı 4002 koduyla kapatılır.

Oturum açmadan önce gelen diğer tüm çerçevelere authentication_required nedeniyle auth_error yanıtı verilir; soket açık kalır.

Kalp atışı ve ön plan durumu

YönÇerçeveDavranış
sunucu → istemci30 sn'de bir {"type":"ping"}{"type":"pong"} ile yanıtlayın.
istemci → sunucu{"type":"ping"}Sunucu {"type":"pong"} ile yanıtlar.
istemci → sunucu{"type":"presence_state","foreground":true}Bu bağlantıyı etkin olarak işaretler.
istemci → sunucu{"type":"presence_state","foreground":false}Bağlantıyı arka planda olarak işaretler; böylece aktarıcı yeni mesajlar için anlık bildirim gönderebilir.

Aktarıcı bir kimliği yalnızca bağlantısı en az 90 saniyede bir ping, pong veya foreground: true içeren presence_state gönderdiği sürece çevrimiçi kabul eder. AeroNyx App ön plandayken 15 saniyede bir ping gönderir ve üçten fazla pong yanıtı kaçırılırsa bağlantıyı kopmuş sayar.

Uzun ömürlü bağlantılar en az 24 saatte bir yeniden bağlanmalıdır. Bir bağlantı canlı çerçeveleri sessizce almayı bıraktığında mesajlar asla kaybolmaz, çünkü her mesaj ayrıca kuyruğa alınır ve oturum açıldığında yeniden oynatılır; ancak canlı teslim yalnızca yeniden bağlandıktan sonra sürer.

Çerçeve kuralları

  • Yalnızca metin çerçeveleri; her çerçevede tek bir JSON nesnesi. İkili çerçeveler yok sayılır.
  • Azami çerçeve boyutu 1.048.576 karakterdir. Daha büyük çerçeveler {"type":"error","reason":"message_too_large"} ile reddedilir. Çerçevenin geri kalanına yer bırakmak için payload_b64 boyutunu yaklaşık 800 KiB'ın altında tutun.
  • Hatalı biçimlendirilmiş çerçeveler invalid_json, invalid_json_type veya unknown_type nedeniyle error döndürür.

Genel hata çerçevesi:

json
{ "type": "error", "reason": "<reason>", "retry_after": 0 }

Hız sınırı hataları ayrıca scope alanını da taşır.

Kapatma kodları

KodAnlamı
1008Host veya Origin'e izin verilmiyor.
4000Sunucu kalp atışını iletemedi.
4001Oturum açma başarısız oldu.
4002Oturum açma zaman aşımına uğradı.

Rastgele sapmalı (jitter) üstel geri çekilmeyle yeniden bağlanın. AeroNyx App, 1–60 saniye aralığına sınırlanmış ve 0,8 ile 1,2 arasında rastgele bir katsayıyla çarpılmış 2^(attempt-1) saniye bekler.

Birebir (1:1) mesaj gönderme

1. Mühürlü zarfı oluşturun

Birebir mesajın yükü, imzalanmış ve şifrelenmiş bir ChatEnvelope nesnesidir. Tam oluşturma yöntemi, Python referans uygulaması ve altın test vektörü Merkezî Sohbet HTTPS API v1: Mühürlü zarf biçimi bölümündedir. Aynı zarf her iki API'de de kullanılır.

Özetle: sohbet anahtarıyla XChaCha20-Poly1305, 121 baytlık bir döküm (transcript) üzerinde Ed25519 imzası ve sabit bir ikili düzen. Ek içeren mesajlar dahil her mesaj için content_type değeri 0'dır.

Açık metin, düz bir mesaj için UTF-8 metindir; ek, yanıt, iletme veya bağlantı önizlemesi içeren mesajlar için ise bir JSON nesnesidir:

json
{
  "type": "aeronyx_message",
  "text": "See the attached file",
  "attachments": [ { "blob_id": "...", "file_key": "...", "media_type": "image/jpeg", "file_name": "photo.jpg", "file_size": 482113 } ],
  "reply": { "msg_id": "...", "sender_pubkey": "...", "text": "..." },
  "forwarded": true,
  "forwarded_from_name": "...",
  "forwarded_from_pubkey": "...",
  "link_preview": { "url": "https://...", "title": "...", "description": "...", "site_name": "..." }
}

type ve text dışındaki tüm alanlar isteğe bağlıdır. Alıcılar, "type": "aeronyx_message" içeren bir JSON nesnesi olmayan her açık metni düz metin olarak göstermelidir. Ek nesnesi "Şifrelenmiş ekler" bölümünde tanımlanmıştır.

2. Çerçeveyi imzalayın

Her mesaj çerçevesi, aktarıcının kabul etmeden önce doğruladığı ikinci bir imza olan payload_sig alanını taşır:

text
payload_sig = Ed25519(identity_key,
    SHA256(receiver_pubkey[32] || sender_pubkey[32] || discriminant as 1 byte
           || timestamp as u64 little-endian || envelope_bytes))

envelope_bytes, payload_b64 değerinin kodu çözülmüş hâlidir. Mesajlar ve düzenlemeler için 11, tepkiler için 12 ayırt edicisini kullanın. payload_sig onaltılık olarak kodlanır.

3. Gönderin

json
{
  "type": "relay_send",
  "msg_id": "9e762ae0f5da43e6bec5eb8143f1f834",
  "receiver_pubkey": "<64 hex>",
  "discriminant": 11,
  "payload_b64": "<base64 envelope>",
  "timestamp": 1780000000,
  "payload_sig": "<128 hex>"
}
AlanKurallar
msg_id32 küçük harfli onaltılık karakter: zarfın 16 baytlık message_id değeri. Alıcı taraftaki uygulama mesajı bu kimlikle saklar; bu nedenle zarfla eşleşmelidir.
receiver_pubkeyAlıcının açık anahtarı.
discriminant11.
timestampUnix saniyesi; sunucu saatinden en fazla ±300 sn sapma.
suppress_pushİsteğe bağlı. true olduğunda anlık bildirim gönderilmez.
contact_requestİsteğe bağlı. Kişi doğrulaması gerektiren birine gönderilen ilk mesajı işaretler (bkz. "Kişi doğrulaması").

4. Onay

json
{ "type": "relay_delivered", "msg_id": "...", "delivered": true, "queued": true, "durable": true }
  • durable (ve queued), mesaj alıcının çevrimdışı kuyruğunda saklandığı anda true olur. durable: true değerini "gönderildi" olarak değerlendirin.
  • delivered, alıcının etkin bir ön plan bağlantısı olduğu anlamına gelir. Alındığının kanıtı değildir; bunun için teslim bilgilerini kullanın.

Denemeyi başarısız saymadan önce onay için en fazla 15 saniye bekleyin.

Retler ve hatalar

json
{ "type": "send_rejected", "msg_id": "...", "reason": "verification_required" }
YanıtNedenEylem
send_rejectedverification_requiredAlıcı yalnızca kişilerinden mesaj kabul ediyor. Yeniden denemeyin.
send_rejectedcontact_request_rate_limitedBu alıcı için kişi isteği sınırına ulaşıldı. Yeniden denemeyin.
errormissing_fieldsZorunlu bir alan eksik veya boş.
errorinvalid_timestamp, timestamp_expiredSaati düzeltin ve zaman damgasını yenileyin.
errorinvalid_payload_sigpayload_sig doğrulanamıyor.
errorrate_limitedretry_after saniye sonra yeniden deneyin.

Yeniden denemeler

Onaylanmamış bir mesajı aynı msg_id ve aynı zarf baytlarıyla yeniden deneyin. Aktarıcı 300 saniyeden eski çerçeveleri reddettiği için her yeniden denemede çerçevenin timestamp ve payload_sig değerlerini yeniden hesaplayın; zarf ise özgün zaman damgasını korur. Aktarıcı ve alıcılar yinelenenleri msg_id üzerinden ayıklar.

HTTPS yedek yolu

WebSocket kullanılamadığında aynı mesaj HTTPS üzerinden gönderilebilir:

http
POST /api/relay/push/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
json
{
  "receiver_pubkey": "<64 hex>",
  "discriminant": 11,
  "payload_b64": "<base64 envelope>",
  "timestamp": 1780000000,
  "payload_sig": "<128 hex>"
}

Başarı, {"success": true} ile birlikte HTTP 200 döndürür. Kişi doğrulaması hataları verification_required veya contact_request_rate_limited ile 400, hız sınırı ise Retry-After ile 429 döndürür. Bu yolla gönderilen mesajlar alıcı için kuyruğa alınır ancak anlık bildirim tetiklemez; bu nedenle WebSocket yeniden bağlandığında mesajı onun üzerinden yeniden gönderin.

Mesajları alma

Gelen mesajlar relay_envelope olarak ulaşır:

json
{
  "type": "relay_envelope",
  "sender_pubkey": "<64 hex>",
  "discriminant": 11,
  "payload_b64": "<base64 envelope>",
  "timestamp": 1780000000,
  "msg_id": "9e762ae0f5da43e6bec5eb8143f1f834",
  "from_offline": false
}

discriminant: 11 için:

  1. Yinelenenleri msg_id üzerinden ayıklayın. Aynı mesaj hem canlı olarak hem de çevrimdışı kuyruktan yeniden gelebilir.
  2. Zarfı ayrıştırın ve zarftaki receiver_pubkey değerinin sizin kimliğiniz olduğunu denetleyin.
  3. Canlı çerçevelerde (from_offline: false), zarfın zaman damgası saatinizden 300 saniyeden fazla sapıyorsa mesajı atın.
  4. Zarf imzasını zarfın sender_pubkey değerine göre doğrulayın. Kimliği doğrulanmış gönderici, çerçevenin sender_pubkey değeri değil, bu anahtardır.
  5. O göndericiden türetilen sohbet anahtarıyla şifreyi çözün. Çok eski uygulama sürümleri ham X25519 çıktısıyla şifreliyordu; HKDF anahtarı başarısız olursa bunu deneyin.
  6. Mesajı kalıcı olarak saklayın, ardından bir teslim bilgisi ve from_offline: true durumunda ayrıca bir çevrimdışı onay gönderin.

Birebir zarflar payload_sig olmadan teslim edilir; özgünlük denetimi zarf imzasıdır. Çerçeveler ayrıca contact_request: true da taşıyabilir.

Bir mesaj size gönderilmemişse, doğrulamadan geçemiyorsa veya şifresi çözülemiyorsa, hiçbir şey göstermeden atın.

Çevrimdışı teslim

Her mesaj, düzenleme, geri çekme, tepki, teslim bilgisi ve okundu bilgisi, canlı teslimden önce alıcının çevrimdışı kuyruğuna yazılır. Kuyruk her oturum açmadan sonra ve istek üzerine otomatik olarak yeniden oynatılır:

json
{ "type": "relay_pull" }

Aktarıcı kuyruktaki tüm öğeleri, from_offline: true ile ve zaman damgasına göre sıralı olarak normal çerçeve türleriyle yeniden oynatır; ardından şunu gönderir:

json
{ "type": "relay_pull_done", "count": 12, "has_more": false }

Teslim en az bir kez garantisiyle yapılır. Öğeler onaylanana kadar kuyrukta kalır:

json
{ "type": "relay_offline_ack", "msg_id": "9e762ae0f5da43e6bec5eb8143f1f834" }

Tepkileri "msg_id" yerine "reaction_id" ile onaylayın. Yalnızca öğe cihazda kalıcı olarak saklandıktan sonra onaylayın. Aktarıcı {"type":"relay_offline_ack","msg_id":"...","success":true} ile yanıt verir.

Kuyruk sınırları:

SınırDeğer
Alıcı başına öğe1.000. Kuyruk dolduğunda yeni öğeler reddedilir ve gönderici durable: false görür.
Saklama süresiEn son öğenin eklenmesinden sonra 72 saat.
Yük boyutuKodu çözülmüş 1 MiB; 1 MiB'lık çerçeve sınırı içinde.

Aktarıcı bir teslim arabelleğidir, mesaj geçmişi değildir. Geçmişi cihazda tutun.

Teslim ve okundu bilgileri

Teslim bilgisi

Bir mesajı sakladıktan sonra gönderin:

json
{ "type": "message_receipt", "receiver_pubkey": "<original sender>", "msg_id": "...", "timestamp": 1780000010 }

Aktarıcı message_receipt_ack ile yanıt verir ve özgün göndericiye {"type":"message_receipt","sender_pubkey":"...","msg_id":"...","timestamp":...} iletir.

Okundu bilgisi

json
{ "type": "message_read", "receiver_pubkey": "<original sender>", "msg_id": "<latest read message>", "timestamp": 1780000200, "enabled": true }

Okundu bilgileri birer eşik işaretidir (watermark): uygulama belirtilen mesajı ve sohbetteki ondan önceki tüm giden mesajları okundu olarak işaretler. Yalnızca kullanıcının okundu bilgileri etkinse gönderin.

Aktarıcı gönderimde, canlı teslimde ve yeniden oynatmada karşılıklılık kuralı uygular. Okundu bilgisi yalnızca iki kullanıcı karşılıklı olarak birbirinin kişisiyse ve her ikisinde de read_receipts_enabled etkinse teslim edilir. Aksi hâlde gönderici şunu alır:

json
{ "type": "message_read_ack", "msg_id": "...", "delivered": false, "suppressed": true, "reason": "receiver_read_receipts_disabled" }
NedenAnlamı
client_disabledÇerçeve enabled: false veya read_receipts_enabled: false taşıyordu.
not_mutual_contactKullanıcılar karşılıklı kişi değil.
reader_read_receipts_disabledOkuyan taraf okundu bilgilerini kapatmış.
receiver_read_receipts_disabledÖzgün gönderici okundu bilgilerini kapatmış.
invalid_pubkeyAçık anahtarlardan biri hatalı biçimlendirilmiş.

Teslim edilen bir okundu bilgisi {"type":"message_read_ack","msg_id":"...","delivered":true} ile onaylanır.

Düzenlemeler ve geri çekmeler

Düzenleme

Düzenleme, yerine geçecek içeriğin tamamını barındıran ve özgün mesaj kimliğine karşı gönderilen yeni bir mühürlü zarftır (kendine ait rastgele bir message_id ile):

json
{
  "type": "message_edit",
  "receiver_pubkey": "<64 hex>",
  "msg_id": "<original msg_id>",
  "target_msg_id": "<original msg_id>",
  "payload_b64": "<base64 envelope>",
  "payload_sig": "<128 hex>",
  "timestamp": 1780000400
}

payload_sig, "Çerçeveyi imzalayın" bölümündeki formülü 11 ayırt edicisiyle kullanır. Tüm ekleri kaldıran bir düzenleme, açık metin JSON'unda "attachments_edited": true değerini ayarlar. Aktarıcı message_edit_ack ile yanıt verir. Alıcılar zarfı bir mesaj gibi doğrular ve şifresini çözer; düzenlemeyi yalnızca göndericisi özgün mesajın yazarıysa uygulamalıdır.

Geri çekme

json
{
  "type": "message_revoke",
  "receiver_pubkey": "<64 hex>",
  "sender_pubkey": "<64 hex>",
  "msg_id": "<original msg_id>",
  "timestamp": 1780000500,
  "payload_sig": "<128 hex>"
}

Geri çekme imzası, karma uygulanmadan ham baytlar üzerinde hesaplanır:

text
payload_sig = Ed25519(identity_key,
    "aeronyx-message-revoke-v1" || sender_pubkey[32] || receiver_pubkey[32]
    || UTF-8(msg_id) || timestamp as u64 little-endian)

Aktarıcı message_revoke_ack ile yanıt verir. Aktarıcı yazarlığı denetlemez: alıcılar imzayı doğrulamalı ve geri çekmeyi yalnızca göndericisi özgün mesajın yazarıysa uygulamalıdır. Geri çekilen bir mesajın eklerini silmek için POST /api/relay/blob/{blob_id}/delete/ çağrısını yapın.

Tepkiler

Birebir tepki, message_id değeri tepki kimliği olan, content_type değeri 2 olan ve açık metni {"emoji": "❤️", "op": "add"} (veya "remove") olan bir mühürlü zarftır:

json
{
  "type": "message_reaction",
  "receiver_pubkey": "<64 hex>",
  "msg_id": "<message being reacted to>",
  "reaction_id": "<32 hex>",
  "payload_b64": "<base64 envelope>",
  "payload_sig": "<128 hex>",
  "timestamp": 1780000300
}
  • payload_sig, 12 ayırt edicisini kullanır.
  • reaction_id, eş güçlülük (idempotency) anahtarıdır. 72 saat içinde yinelenen bir reaction_id, "duplicate": true ile onaylanır ve yeniden teslim edilmez.
  • Aktarıcı {"type":"message_reaction_ack","msg_id":"...","reaction_id":"...","delivered":...,"queued":...} ile yanıt verir.
  • Tepkiler, hız penceresi içinde gönderici ve sohbet başına 20 ile sınırlıdır.

Grup tepkileri "Gruplar" bölümünde açıklanmıştır.

Çevrimiçi durumu ve yazıyor göstergesi

Çevrimiçi durumu ve yazıyor çerçeveleri açık metin meta verilerdir ve aktarıcı tarafından görülebilir.

Çevrimiçi durumu

Kişilere abone olun:

json
{ "type": "presence_subscribe", "pubkeys": ["<64 hex>", "<64 hex>"] }

Çerçeve başına en fazla 200 anahtar dikkate alınır; hatalı biçimlendirilmiş ve yinelenen anahtarlar yok sayılır. Abonelikler bağlantının ömrü boyunca birikir. Yalnızca kendi kişilerinize abone olun.

json
{
  "type": "presence_subscribe_ack",
  "count": 2,
  "updates": [
    { "pubkey": "<a>", "visible": true, "presence_visible": true, "last_seen_visible": true, "online": false, "last_seen_ts": 1780000000, "reason": "allowed" },
    { "pubkey": "<b>", "visible": false, "presence_visible": false, "last_seen_visible": false, "reason": "not_mutual_contact" }
  ],
  "server_ts": 1780000001
}

Çevrimiçi durumu yalnızca karşılıklı kişiler arasında ve yalnızca hedefte presence_enabled etkinse görülebilir. Gizli girdiler (reason değeri not_mutual_contact veya presence_hidden olanlar) online veya last_seen_ts içermez. last_seen_ts yalnızca last_seen_visible değeri true olduğunda bulunur; aksi hâlde "yakın zamanda görüldü" gibi genel bir durum gösterin.

Canlı değişiklikler şu şekilde gelir:

json
{ "type": "presence_update", "pubkey": "<a>", "online": true, "presence_visible": true, "last_seen_visible": true, "last_seen_ts": 1780000100 }

Yazıyor göstergesi

json
{ "type": "typing", "receiver_pubkey": "<64 hex>", "is_typing": true }
{ "type": "group_typing", "group_id": "<uuid>", "is_typing": true }

Yazıyor göstergesi yalnızca göndericinin çevrimiçi durumu alıcıya görünür olacaksa (karşılıklı kişiler ve presence_enabled) ya da göndericinin üyesi olduğu bir grubun diğer üyelerine iletilir. Hiçbir zaman saklanmaz, kuyruğa alınmaz veya anlık bildirim olarak gönderilmez.

Profil ve gizlilik ayarları

http
GET /api/relay/profile/
Authorization: Relay <pubkey>:<timestamp>:<signature>
json
{
  "success": true,
  "profile": {
    "pubkey_hex": "<64 hex>",
    "display_name": "AeroNyx User",
    "bio": "",
    "handle": "",
    "avatar_url": "",
    "status_text": "",
    "privacy": { "presence_enabled": true, "last_seen_enabled": true, "read_receipts_enabled": true },
    "updated_at": "2026-10-09T10:00:00Z"
  }
}

Profili olmayan bir kimlik boş alanlar alır ve üç gizlilik bayrağının tümü true olur.

http
PATCH /api/relay/profile/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
json
{ "display_name": "Alice", "privacy": { "presence_enabled": true, "last_seen_enabled": false, "read_receipts_enabled": false } }
AlanKurallar
display_nameEn fazla 50 karakter.
bioEn fazla 200 karakter.
avatar_urlhttps:// URL'si veya boş.
handlea-z ve 0-9, 5–24 karakter. Kullanıcı adları üyelik kurallarına ve değişiklik bekleme sürelerine tabidir.
privacy.*Mantıksal değerler. Üç bayrak üst düzeyde de gönderilebilir.

Hatalar arasında no_valid_fields, <flag>_invalid_boolean, handle_taken ve handle_change_cooldown:<date> bulunur.

İstemciyi bu ayarlarla tutarlı tutun: okundu bilgileri kapalıyken okundu bilgisi göndermeyin ve kendi okundu bilgileriniz kapalıyken karşı tarafın okundu durumunu göstermeyin.

Kişi doğrulaması

Bir kullanıcı, yabancıların kendisine mesaj göndermeden önce doğrulanmasını şart koşabilir. Alıcı bu özelliği açmışsa ve göndericiyi kişi olarak eklememişse relay_send, verification_required ile reddedilir.

Bir sohbet başlatmak için "contact_request": true içeren tek bir mesaj gönderin. Kişi istekleri bu denetimi atlar ve kayan 24 saatlik bir pencere içinde gönderici ve alıcı başına 3 ile sınırlıdır; sonraki istekler contact_request_rate_limited ile reddedilir. Uygulamanın mesajı bir istek olarak sunabilmesi için contact_request bayrağı alıcıya iletilir.

Kişi doğrulaması relay_send ve HTTPS yedek yolu için geçerlidir.

Gruplar

Grup mesajları

Grup içeriği, AES-256-GCM kullanılarak 32 baytlık paylaşılan bir grup anahtarıyla şifrelenir:

text
payload_b64 = base64(nonce[12] || AES-256-GCM(group_key, plaintext_json) || tag[16])

Açık metin JSON; text, type (text, media, system veya reaction), sender_pubkey, created_at ve isteğe bağlı olarak attachments, mentions, reply, forwarded, forwarded_from_name, forwarded_from_pubkey ve link_preview alanlarını içerir.

json
{
  "type": "group_send",
  "msg_id": "<32 hex>",
  "group_id": "<uuid>",
  "payload_b64": "<base64>",
  "timestamp": 1780000000,
  "payload_sig": "<128 hex>",
  "key_version": 3
}
text
payload_sig = Ed25519(identity_key,
    SHA256(UTF-8(group_id) || sender_pubkey[32] || 0x19 || timestamp as u64 little-endian
           || decoded payload))

Aktarıcı imzayı ve göndericinin etkin bir üye olduğunu denetler, mesajı diğer tüm etkin üyeler için saklar ve ardından canlı olarak teslim eder. Grup yükleri birebir zarfı kullanmaz; grup zarfları, alıcıların şifreyi çözmeden önce göndericiyi doğrulayabilmesi için group_id, key_version ve payload_sig ile teslim edilir.

json
{
  "type": "group_delivered",
  "msg_id": "...",
  "group_id": "...",
  "accepted": true,
  "accepted_count": 5,
  "delivered_count": 2,
  "queued_count": 5,
  "failed_count": 0,
  "member_count": 6
}

Üye olmayan bir gönderici not_a_member nedeniyle error alır.

Grup düzenlemeleri, geri çekmeleri ve tepkileri

Çerçeveİmza
group_message_edit (group_id, msg_id, target_msg_id, payload_b64, payload_sig, key_version, timestamp)Yukarıdaki grup formülü.
group_message_reaction (group_id, msg_id, reaction_id, payload_b64, payload_sig, key_version, timestamp)Yukarıdaki grup formülü. Yük, type: "reaction" içeren bir grup yüküdür.
group_message_revoke (group_id, sender_pubkey, msg_id, timestamp, payload_sig)`"aeronyx-group-message-revoke-v1"

Her biri, teslim sayılarını taşıyan karşılık gelen _ack çerçevesiyle onaylanır. Alıcılar düzenlemeleri ve geri çekmeleri yalnızca özgün yazardan geliyorsa uygular.

Grup anahtarları

Grup anahtarları, grup sahibi tarafından üye başına anahtar paketleri olarak dağıtılır: base64(nonce[12] || AES-256-GCM(chat_key(owner, member), group_key) || tag[16]). /api/relay/groups/ altındaki REST uç noktaları grup oluşturur, üyeleri ve davetleri yönetir, anahtar paketlerini yükler, anahtarları döndürür (keys/rotate/) ve çağıranın geçerli paketini getirir (keys/me/). Göndericiler sahip oldukları en son anahtar sürümüyle şifreler; bir anahtar sürümüne sahip olmayan alıcılar keys/me/ uç noktasından anahtarı getirmeli ve anahtar gelene kadar mesajı bekletmelidir.

Şifrelenmiş ekler

Ekler cihazda şifrelenir, opak şifreli metin olarak yüklenir ve şifrelenmiş mesajın içinden başvurulur.

Dosyayı şifreleyin

Her dosya için rastgele 32 baytlık bir anahtar ve rastgele 12 baytlık bir nonce üretin:

text
blob = nonce[12] || AES-256-GCM(file_key, file_bytes) || tag[16]

blob verisini yükleyin. file_key değerini ve tüm tanımlayıcı alanları yükleme isteğine asla koymayın, şifrelenmiş mesajın içine koyun.

Ek nesnesi

AnahtarZorunluAnlamı
blob_idevetYüklemenin döndürdüğü kimlik.
file_keyevet32 baytlık dosya anahtarının Base64 hâli.
media_typeevetAçık metin dosyanın MIME türü.
file_nameevetGörünen ad.
file_sizeevetBayt cinsinden açık metin boyutu.
thumb_b64hayırBase64 JPEG küçük resim, en fazla 64 KiB.
duration_mshayırSes veya video süresi.
waveformhayırSesli mesajlar için [0, 1] aralığında en fazla 96 sayı.
sticker, sticker_pack, sticker_posehayırÇıkartma kimliği.
livehayırLive Photo hareket bölümü: {blob_id, file_key, media_type, file_size, duration_ms?, width?, height?}.

Alıcılar blob_id veya file_key içermeyen ekleri yok sayar. Uygulamadan gelen sesli mesajlar, MP4 kapsayıcısında AAC-LC biçimindedir (audio/mp4).

Yükleme: tek istek (en fazla 10 MiB)

http
POST /api/relay/blob/presign/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
json
{ "file_size": 482141, "media_type": "image/jpeg", "media_kind": "image", "ttl_days": 7 }

file_size, şifreli metin boyutudur. media_kind şunlardan biridir: voice, image, video, file, avatar, other. ttl_days 1–30 aralığına sınırlanır (varsayılan 7).

json
{
  "blob_id": "<uuid>",
  "upload_url": "https://...",
  "upload_method": "PUT",
  "storage": "r2",
  "expires_at": "2026-10-16T10:00:00Z",
  "media_type": "image/jpeg",
  "media_kind": "image",
  "access_mode": "capability",
  "ttl_days": 7,
  "max_bytes": 10485760
}

Ardından:

  1. Şifreli metni 15 dakika içinde, yalnızca bir Content-Type başlığıyla upload_url adresine PUT ile gönderin. Authorization başlığını depolama hizmetine göndermeyin.
  2. RelayAuth ile POST /api/relay/blob/{blob_id}/complete/ çağrısını yapın. Aktarıcı nesneyi doğrular ve {blob_id, file_size, expires_at, storage} döndürür.

Yükleme: çok parçalı (en fazla 100 MiB)

http
POST /api/relay/blob/multipart/create/
json
{ "total_size": 52428800, "media_type": "video/mp4", "media_kind": "video", "ttl_days": 7 }
json
{
  "blob_id": "<uuid>",
  "upload_id": "...",
  "part_size": 8388608,
  "total_parts": 7,
  "part_urls": ["https://...", "..."],
  "storage": "r2",
  "expires_at": "...",
  "max_bytes": 104857600
}

part_size varsayılan olarak 8 MiB'tır ve 5 ile 16 MiB arasında bir değer istenebilir. Parça URL'leri 60 dakika geçerlidir. Her parçayı kendi URL'sine PUT ile gönderin ve ETag yanıt başlığını kaydedin, ardından:

http
POST /api/relay/blob/multipart/complete/
json
{ "blob_id": "<uuid>", "upload_id": "...", "parts": [ { "part_number": 1, "etag": "\"...\"" } ] }

AeroNyx App, 8 MiB'a kadar şifreli metin için tek istekli yüklemeyi, bunun üzerinde ise çok parçalı yüklemeyi kullanır.

İndirme

http
GET /api/relay/blob/{blob_id}/

Aktarıcı, içerik dağıtım ağındaki bir Location ile ve X-AeroNyx-Blob-Size, X-AeroNyx-Blob-Media-Type ve X-AeroNyx-Blob-Storage başlıklarıyla 302 yanıtı verir. Yönlendirmeyi hiçbir Authorization başlığını iletmeden kendiniz izleyin, ardından blob'u file_key ile doğrulayın ve şifresini çözün. İndirmeyi beklenen boyutla sınırlayın.

Bir blob_id, taşıyıcı yetkisidir (bearer capability): ona sahip olan herkes şifreli metni getirebilir; anahtarın yalnızca şifrelenmiş mesajın içinde taşınmasının nedeni budur. access_mode ve sona erme süresi aktarıcının yönlendirmesinde uygulanır. Gizlilik için bunlara güvenmeyin.

Ekleri silme

http
POST /api/relay/blob/{blob_id}/delete/

Bir blob'u yalnızca onu yükleyen silebilir. Yanıt {"blob_id": "...", "deleted": true} şeklindedir.

Ek hataları

Hatalar {"success": false, "error": "<text>", "error_code": "<code>"} biçimini kullanır. Akışı error_code değerine göre dallandırın.

HTTPerror_codeAnlamı
400blob_id_invalidHatalı biçimlendirilmiş blob kimliği.
400blob_missing_file_size, blob_missing_total_size, blob_missing_parts, blob_bad_parts, blob_bad_part_countGeçersiz yükleme isteği.
400blob_not_r2, blob_multipart_complete_failedTamamlama başarısız oldu; yeni bir yükleme başlatın.
401auth_requiredBlob, RelayAuth gerektiriyor.
403blob_not_uploader, download_forbiddenÇağıranın izni yok.
404blob_not_found, blob_not_uploadedBilinmeyen blob veya yükleme bitmeden yapılan tamamlama isteği.
410blob_expiredBlob'un süresi doldu. Göndericiden yeniden göndermesini isteyin.
413blob_too_largeSınır aşıldı; yanıt max_bytes ve chunked_max_bytes içerir.
503blob_r2_unavailableDepolama geçici olarak kullanılamıyor; geri çekilmeyle yeniden deneyin.

Eski yükleme uç noktaları

POST /api/relay/blob/ (çok parçalı form, en fazla 10 MiB) ve /api/relay/blob/session/ altındaki sürdürülebilir oturum API'si (en fazla 100 MiB, 64 KiB ile 4 MiB arası parçalar, 24 saat geçerli oturumlar) yedek olarak kullanılabilir durumdadır. Yeni istemciler yukarıdaki uç noktaları kullanmalıdır.

Anlık bildirimler

Aktarıcı, iOS ve macOS için Apple Push Notification service (APNs) bildirimleri gönderir. Android istemcileri mesajları yalnızca WebSocket üzerinden alır.

Alıcının etkin bir ön plan bağlantısı yoksa, gönderici suppress_push ayarlamamışsa ve alıcı sohbeti sessize almamışsa relay_send ve group_send için anlık bildirim gönderilir. Düzenlemeler, geri çekmeler, tepkiler ve teslim/okundu bilgileri anlık bildirim göndermez. Anlık bildirim yükleri hiçbir şifreli metin içermez:

json
{
  "aps": { "alert": { "title": "AeroNyx", "body": "New encrypted message" }, "sound": "default", "badge": 1, "content-available": 1 },
  "kind": "p2p_message",
  "sender_pubkey": "<64 hex>",
  "message_id": "..."
}

kind, p2p_message (sender_pubkey ile) veya group_message (group_id ile) değerini alır. Arama bildirimleri missed_call ve aramaya özel yükler kullanır. Anlık bildirim aldığınızda bağlanın ve relay_pull çalıştırın.

Uç noktaGövde
POST /api/relay/push/register/token (64 onaltılık karakter), platform (ios veya macos), bundle_id, environment (production veya sandbox), isteğe bağlı token_type (alert veya voip) ve provider (apns).
POST /api/relay/push/unregister/token, isteğe bağlı platform, token_type, provider.
POST /api/relay/push/mute/kind (p2p veya group), target (açık anahtar veya grup kimliği), muted (mantıksal değer).

Üçü de RelayAuth gerektirir. Bir belirtecin kaydedilmesi, onu çağıran kimliğe taşır.

Aramalar

Sesli ve görüntülü arama sinyalleşmesi, aynı WebSocket üzerinden açık metin meta veri olarak iletilir; medya ayrı akar. Çerçeveler birebir aramalar için call_invite, call_answer, call_reject, call_hangup ve call_busy; gruplar için group_call_invite, group_call_invite_broadcast, group_call_answer ve group_call_hangup_broadcast'tır; barındırılan toplantılar için ayrıca toplantıya kabul çerçeveleri bulunur.

Aktarıcı room_name değerini katılımcılara göre doğrular: birebir aramalar için p2p_ ve ardından SHA256(lower_key + ":" + higher_key) değerinin ilk 16 onaltılık karakteri; gruplar için grp_<first 8 characters of group_id>_<first 8 hex of SHA256(group_id)>. Çevrimdışı bir alıcıya yönelik arama sinyalleri 120 saniye bekletilir.

Hız sınırları

KapsamSınırYanıt
Kimlik başına relay_send, group_send ve HTTPS pushKısa pencere başına 50; günde 100.000WebSocket: retry_after ile error rate_limited. HTTPS: Retry-After ile 429.
Gönderici ve grup başına group_sendKısa pencere başına 10error rate_limited, scope: "sender".
Grup başına group_sendKısa pencere başına 50error rate_limited, scope: "group".
Gönderici ve sohbet başına tepkilerKısa pencere başına 20error rate_limited, scope: "reaction".
Gönderici ve alıcı başına kişi istekleri24 saatte 3send_rejected contact_request_rate_limited.

En az retry_after saniye geri çekilin. Sıkı bir döngü içinde yeniden göndermeyin: siz yeniden denerken sayaçlar işlemeye devam eder.

Uygulama kontrol listesi

  1. Bir Ed25519 kimliği üretin ve saklayın; her yerde küçük harfli onaltılık anahtarlar kullanın.
  2. RelayAuth'u ve WebSocket oturum açma, kalp atışı ve presence_state işlevlerini uygulayın.
  3. Mühürlü zarfı uygulayın ve Merkezî Sohbet HTTPS API v1 içindeki altın vektöre göre doğrulayın.
  4. relay_send ile gönderin, durable: true değerini gönderildi olarak değerlendirin, yeniden denemelerde timestamp ve payload_sig değerlerini yenileyin.
  5. relay_envelope alın: yinelenenleri ayıklayın, doğrulayın, şifreyi çözün, saklayın, ardından message_receipt ve relay_offline_ack gönderin.
  6. Oturum açtıktan sonra ve anlık bildirimle uyandırıldığınızda relay_pull çalıştırın; yalnızca kalıcı depolamadan sonra onaylayın.
  7. Profil gizlilik bayraklarını okuyun ve çevrimiçi durumu ile okundu bilgilerinde bunlara uyun.
  8. Ekleri cihazda şifreleyin ve presign veya çok parçalı yükleme ile yükleyin; file_key değerini şifrelenmiş mesajın içinde tutun.
  9. Düzenlemeleri ve geri çekmeleri uygulamadan önce yazarlığı doğrulayın.
  10. Mesaj aramasını ve geçmişi cihazda tutun. Aktarıcıda içerik araması yoktur ve aktarıcı bir arşiv değildir.
<!-- faq:start -->

Sıkça sorulan sorular

AeroNyx Sohbet Aktarıcısı mesajlarımı okuyabilir mi?

Hayır. Mesajlar, düzenlemeler, tepkiler, grup mesajları ve ekler aktarıcıya ulaşmadan önce göndericinin cihazında şifrelenir ve imzalanır; anahtarlar ise konuşmadaki kişilerin cihazlarından hiçbir zaman çıkmaz. Aktarıcı yalnızca şifreli metni saklar ve iletir.

AeroNyx Sohbet Aktarıcısı neleri görebilir?

Aktarıcı teslim meta verilerini görür: gönderici ve alıcı açık anahtarları, grup ve mesaj kimlikleri, zaman damgaları, yük boyutları, teslim ve okundu durumu, çevrimiçi durumu ve yazıyor sinyalleri, arama sinyalleşmesi meta verileri, ek boyutları ve bağlantı IP adresleri. Mesaj içeriğini, ek içeriğini veya anahtarları görmez. Tam liste, bu sayfanın başındaki güven modelinde yer alır.

AeroNyx sohbeti hangi şifrelemeyi kullanır?

Her kimlik bir Ed25519 anahtar çiftidir. İki kişi, X25519 ve HKDF-SHA256 ile ortak bir sohbet anahtarı türetir. Birebir (1:1) mesajlar XChaCha20-Poly1305 ile şifrelenir ve Ed25519 ile imzalanır. Grup mesajları ve ekler AES-256-GCM ile şifrelenir. Tam bayt biçimleri ve bir test vektörü, Merkezî Sohbet HTTPS API v1 belgelerinde yayımlanmıştır.

Fotoğraflar, videolar ve dosyalar nasıl korunur?

Her dosya, yüklenmeden önce cihazda kendine ait rastgele bir AES-256-GCM anahtarıyla şifrelenir. Depolama yalnızca şifreli metni alır. Dosya anahtarı uçtan uca şifrelenmiş mesajın içinde taşınır; bu nedenle dosyanın şifresini yalnızca alıcılar çözebilir.

Alıcı çevrimdışıysa ne olur?

Aktarıcı, şifrelenmiş mesajları alıcının çevrimdışı kuyruğunda en fazla 72 saat tutar ve alıcı yeniden bağlandığında teslim eder. iOS ve macOS'ta alıcı ayrıca mesaj içeriği barındırmayan bir anlık bildirim alır.

AeroNyx sohbet geçmişimi saklıyor mu?

Hayır. Aktarıcı bir teslim arabelleğidir: öğeler, alıcının cihazı bunları sakladığını onayladıktan sonra silinir. Sohbet geçmişi ve arama sizin cihazlarınızda bulunur.

Kendi AeroNyx istemcimi veya botumu geliştirebilir miyim?

Evet. Bir Ed25519 kimliğine sahip olan ve bu sayfadaki biçimleri uygulayan her yazılım, AeroNyx App kullanıcılarıyla mesaj alışverişi yapabilir. WebSocket kullanmayan, daha basit ve istek/yanıt tabanlı bir entegrasyon için Merkezî Sohbet HTTPS API v1'i kullanın.

AeroNyx Sohbet Aktarıcısı merkeziyetsiz mi?

Sohbet Aktarıcısı, AeroNyx'in merkezî teslim hizmetidir. AeroNyx ayrıca sohbet şifreli metnini ağ çeşitliliğine sahip iki atlamalı bir rota üzerinden taşıyabilen açık kaynaklı (AGPL-3.0) bir düğüm ağı işletir. İki yol bir arada var olur: aktarıcı hızlı ve güvenilir teslim ile çevrimdışı kuyruklar sağlar; düğüm yolu ise herhangi bir tekil operatörün gözlemleyebileceklerini azaltan isteğe bağlı bir rotadır.

Mesajım neden verification_required ile reddediliyor?

Alıcı yalnızca kişilerinden gelen mesajları kabul eder. contact_request: true içeren tek bir ilk mesaj gönderin; alıcı bunu bir kişi isteği olarak görür. Her alıcı için herhangi bir 24 saatlik zaman aralığında en fazla üç kişi isteğine izin verilir.

<!-- faq:end --> <!-- verified-two-hop-delivery-v1:start -->

Doğrulanmış iki atlamalı teslim

Uygun ve kimliği doğrulanmış ChatRelay trafiğinde kaynak, ağ çeşitliliğine sahip iki atlamalı bir yol seçebilir ve teslimi ancak beklenen uç düğümün imzalı alındısını doğruladıktan sonra sayabilir. Aktarıcı düğümler şifreli metni yönlendirir ve uçtan uca (E2E) yükü ayrıştırmaz. Kanıt modelinin tamamı için Düğüm Keşfi ve Doğrulanmış Şifreli Aktarıcı Teslimi sayfasına bakın.

<!-- verified-two-hop-delivery-v1:end -->