Yeyra v1 API (M2M)
Dış sistemlerin (örn. Addore orkestratörü) Yeyra'ya makine-makine bağlanması için API katmanı.
Kimlik Doğrulama
- Dashboard → Ayarlar → API sekmesinden anahtar oluşturun. Ham anahtar (
yk_...) yalnızca oluşturma anında bir kez gösterilir — güvenli bir yere kaydedin. Sunucuda yalnızca SHA-256 hash'i saklanır. - Her isteğe header ekleyin:
Authorization: Bearer yk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxScope'lar (anahtar oluştururken seçilir):
| Scope | Verdiği yetki |
|---|---|
posts:write | POST /api/v1/posts |
generations:write | POST /api/v1/ai/generations |
jobs:read | GET /api/v1/jobs/{id} |
upload:write | POST /api/v1/upload |
brands:read | GET /api/v1/brands |
Rate limit: anahtar başına 60 istek/dakika. Aşımda 429.
Hata formatı (tüm endpoint'lerde ortak):
{ "error": "İnsan-okur mesaj", "code": "HATA_KODU" }| HTTP | Anlamı |
|---|---|
| 401 | Anahtar yok / geçersiz / iptal edilmiş / süresi dolmuş |
| 403 | Scope yetersiz veya plan limiti (code: PLAN_LIMIT) |
| 400 | Validasyon hatası |
| 404 | Kayıt bulunamadı ya da size ait değil |
| 429 | Rate limit aşıldı |
| 503 | Depolama servisi yapılandırılmamış (STORAGE_UNAVAILABLE) |
Endpoint'ler
Base URL: https://yeyra.com (geliştirmede http://localhost:3000)
POST /api/v1/posts — Post oluştur
Scope: posts:write. Mevcut panel akışıyla birebir aynı kurallar geçerlidir (plan limitleri, carousel/reel/ilk-yorum feature gate'leri, geçmiş tarihe zamanlama yasağı).
Body:
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
accountId | string | ✅ | Instagram hesap ID (kullanıcıya ait ve aktif olmalı) |
facebookPageId | string | — | Çapraz paylaşım için Facebook sayfa ID |
caption | string ≤2200 | — | Açıklama |
mediaType | IMAGE | CAROUSEL | VIDEO | REEL | STORY | ✅ | |
mediaUrls | string[] (min 1) | ✅ | Mutlak URL veya /api/cdn/... yolu (upload endpoint'inin döndürdüğü publicUrl) |
thumbnailUrl | string | — | Video kapak görseli |
hashtags | string[] | — | |
firstComment | string ≤2200 | — | İlk yorum (plan gerektirir) |
locationId / locationName | string | — | |
status | DRAFT | SCHEDULED | — | Varsayılan DRAFT |
scheduledAt | ISO 8601 | SCHEDULED ise ✅ | Gelecekte olmalı |
autoDeleteAt | ISO 8601 | — | Yayın tarihinden sonra olmalı |
sponsoredLabel | string ≤50 | — |
curl -X POST https://yeyra.com/api/v1/posts \
-H "Authorization: Bearer $YEYRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "clxx_instagram_account_id",
"caption": "Yeni koleksiyon yayında! ✨",
"mediaType": "IMAGE",
"mediaUrls": ["/api/cdn/media/u_123/abc.jpg"],
"hashtags": ["moda", "yenisezon"],
"status": "SCHEDULED",
"scheduledAt": "2026-06-15T18:30:00.000Z"
}'Cevap 201: { "post": { "id", "status", "scheduledAt", ... } } — post.id değerini jobs endpoint'inde takip için kullanın. SCHEDULED post'lar otomatik kuyruğa alınır ve zamanı gelince yayınlanır.
POST /api/v1/ai/generations — AI üretimi tetikle
Scope: generations:write. AI pipeline'ı şablon (AiTemplate) tabanlıdır; şablon marka profili, konu havuzu ve stil ayarlarını içerir.
Body: { "templateId": "clxx_template_id" }
curl -X POST https://yeyra.com/api/v1/ai/generations \
-H "Authorization: Bearer $YEYRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "templateId": "clxx_template_id" }'Cevap:
- Kuyruk modunda (Redis var)
202:{ "generationId": null, "jobId": "...", "status": "QUEUED" }— sonuç içingeneration.completedwebhook'unu dinleyin. - Inline modda
201:{ "generationId": "...", "status": "PENDING" | "APPROVED", "postId": "..." | null }—generationIdilejobsendpoint'inden durum sorgulanabilir. - Her iki modda
X-AI-RateLimit-Limit/X-AI-RateLimit-Remainingheader'ları döner.
GET /api/v1/jobs/{id} — Birleşik durum sorgusu
Scope: jobs:read. id bir post ID'si veya generation ID'si olabilir; tek endpoint'ten birleşik cevap döner.
curl https://yeyra.com/api/v1/jobs/clxx_post_or_generation_id \
-H "Authorization: Bearer $YEYRA_API_KEY"Cevap 200:
{
"id": "clxx...",
"type": "post",
"status": "PUBLISHED",
"errorMessage": null,
"permalink": "https://www.instagram.com/p/...",
"imageUrl": "/api/cdn/media/...",
"postId": null,
"createdAt": "...", "updatedAt": "...",
"scheduledAt": "...", "publishedAt": "..."
}type: "post"→ status:DRAFT | SCHEDULED | PUBLISHING | PUBLISHED | FAILED | CANCELLEDtype: "generation"→ status:PENDING | APPROVED | REJECTED | PUBLISHED | FAILED;postIddoluysa üretimden post oluşturulmuştur.
POST /api/v1/upload — Presigned yükleme URL'i
Scope: upload:write. Dosya Yeyra sunucusuna değil, doğrudan R2 depolamaya yüklenir.
Body: { "mimeType": "image/jpeg", "fileName": "opsiyonel.jpg" } İzinli formatlar: image/jpeg, image/png, image/webp, image/gif, video/mp4, video/quicktime.
# 1. Presigned URL al
curl -X POST https://yeyra.com/api/v1/upload \
-H "Authorization: Bearer $YEYRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "mimeType": "image/jpeg" }'
# → { "uploadUrl": "https://...r2...", "publicUrl": "/api/cdn/media/u_123/abc.jpg", "key": "media/u_123/abc.jpg" }
# 2. Dosyayı doğrudan R2'ye PUT et (15 dk geçerli)
curl -X PUT "$UPLOAD_URL" -H "Content-Type: image/jpeg" --data-binary @foto.jpg
# 3. publicUrl'i posts endpoint'inde mediaUrls içinde kullanGET /api/v1/brands — Marka profilleri
Scope: brands:read. Dış sistemin marka eşleştirmesi için.
curl https://yeyra.com/api/v1/brands -H "Authorization: Bearer $YEYRA_API_KEY"Cevap 200: { "brands": [{ "id", "name", "website", "logoUrl", "colorPalette", "brandVoice", "audience", "description", "createdAt" }] }
Webhook'lar (Yeyra → dış sistem)
Dashboard → Ayarlar → API → Webhook Endpoint'leri bölümünden URL + olay aboneliği ekleyin. Secret otomatik üretilir (veya kendiniz verebilirsiniz) ve imza doğrulamada kullanılır.
Olaylar:
| Olay | Ne zaman | data içeriği |
|---|---|---|
post.published | Post platformda yayınlandığında | postId, platform, permalink, publishedAt |
post.failed | Yayınlama kalıcı olarak başarısız olduğunda | postId, platform, errorMessage |
generation.completed | AI üretimi tamamlandığında | generationId, imageUrl, caption, status |
generation.failed | AI üretimi başarısız olduğunda (son denemede) | generationId, error |
İstek formatı: POST + JSON:
{ "event": "post.published", "timestamp": "2026-06-12T18:00:00.000Z", "data": { ... } }Header'lar:
Content-Type: application/json
X-Yeyra-Event: post.published
X-Yeyra-Signature: sha256=<HMAC-SHA256(secret, ham_body)>Teslimat garantisi: 10 sn timeout; 2xx dışı cevapta olay kuyruğa yazılır ve 15 dakikada bir çalışan retry cron'u en fazla 3 deneme yapar.
İmza doğrulama örneği (Node.js)
import crypto from "crypto";
export function verifyYeyraSignature(rawBody, signatureHeader, secret) {
const expected =
"sha256=" +
crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
// Zamanlama saldırılarına karşı sabit süreli karşılaştırma
return (
signatureHeader?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected))
);
}
// Express örneği — imza HAM body üzerinden hesaplanır, JSON.parse'tan ÖNCE alın:
app.post("/webhooks/yeyra", express.raw({ type: "application/json" }), (req, res) => {
if (!verifyYeyraSignature(req.body, req.get("X-Yeyra-Signature"), process.env.YEYRA_WEBHOOK_SECRET)) {
return res.status(401).send("invalid signature");
}
const { event, data } = JSON.parse(req.body);
// ... olayı işle
res.sendStatus(200);
});Tipik Addore akışı
1. GET /api/v1/brands → marka eşleştir
2. POST /api/v1/upload + R2 PUT → medyayı yükle
3. POST /api/v1/posts (SCHEDULED) → post'u zamanla
4. Webhook post.published / post.failed → sonucu al
(veya GET /api/v1/jobs/{postId} ile poll et)