توسعه‌دهندگان

پوشه را در نرم‌افزار خودتان به کار ببرید

فایل آپلود کنید، پوشه بسازید، لینک اشتراک امن با تاریخ انقضا بدهید، مخاطب و پیش‌فاکتور ثبت کنید و از بازدیدها با وب‌هوک باخبر شوید. REST API نسخه ۱ با ۶۴ عملیات مستند، خطاهای استاندارد و SDK تایپ‌اسکریپت.

  • فایل و پوشه

    آپلود تا سقف هر فایل، آپلود چندبخشی قابل ادامه، دانلود و نسخه‌ها

  • لینک امن

    انقضا، رمز، هویت تأییدشده، واترمارک و آمار بازدید

  • CRM و پیش‌فاکتور

    مخاطب، شرکت، فرصت فروش، پیش‌فاکتور رسمی با PDF

  • وب‌هوک امضاشده

    آماده شدن فایل، باز شدن لینک، پاسخ بیننده و…

شروع سریع

  1. در پنل، تنظیمات ← پیشرفته ← API و وب‌هوک یک کلید بسازید و فقط دامنه‌های لازم را بدهید (در پلن‌های کسب‌وکار و تیم).
  2. کلید را فقط یک بار می‌بینید؛ آن را در متغیر محیطی سرورتان بگذارید، نه در کد.
  3. اولین درخواست را بفرستید: فایلی آپلود کنید و برایش لینک اشتراک بسازید.
export POOSHE=https://pooshe.cloud/api/v1
export KEY=slk_…   # تنظیمات ← پیشرفته ← کلیدهای API

# ۱) شروع آپلود: اندازه دقیق فایل را بدهید
curl -sS "$POOSHE/uploads" \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"fileName":"proposal.pdf","size":'$(wc -c < proposal.pdf)'}'
# → {"documentId":"…","versionId":"V","maxBytes":…}

# ۲) ارسال محتوا و ۳) نهایی‌سازی
curl -sS -X PUT "$POOSHE/uploads/V/content" -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/octet-stream" --data-binary @proposal.pdf
curl -sS -X POST "$POOSHE/uploads/V/finalize" -H "Authorization: Bearer $KEY"

# ۴) پس از آماده شدن (GET /versions/V → "ready")، لینک ۷ روزه بدون دانلود
curl -sS "$POOSHE/links" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"documentId":"D","name":"برای شرکت نمونه","expiresInDays":7,"allowDownload":false}'

برای اطمینان از کلید: GET /api/v1/key نام فضای کاری، دامنه‌های مؤثر و سقف نرخ کلید را برمی‌گرداند.

احراز هویت و دسترسی

هر درخواست سرآیند Authorization: Bearer slk_… دارد. کلید به‌جای عضوی که آن را ساخته عمل می‌کند و همیشه با نقش فعلی او: اگر عضو از تیم حذف شود یا نقشش محدود شود، کلید هم همان لحظه محدود می‌شود. هر کلید فقط به منابع فضای کاری خودش دسترسی دارد.

دامنه‌های کلید API
دامنهچه چیزیمسیرها
files:read
files:write
فایل‌ها، پوشه‌ها، آپلود، نسخه‌ها، دانلود و سطل زباله/drive، /uploads، /upload-sessions، /documents، /versions
sharing:read
sharing:write
لینک‌های اشتراک و آمار بازدید آن‌ها/links
crm:read
crm:write
مخاطبان، شرکت‌ها، سرنخ‌ها، پیگیری‌ها، یادداشت‌ها، فرصت‌ها و پاسخ بینندگان/contacts، /companies، /leads، /followups، /notes، /opportunities، /responses
quotes:read
quotes:write
کاتالوگ کالا و خدمات و پیش‌فاکتورها/catalog، /quotes
analytics:read
analytics:write
گزارش تیم/analytics
  • GET به دامنه read و بقیه روش‌ها به write نیاز دارند. دامنه قدیمی read یا write یعنی همه منابع.
  • می‌توانید کلید را به نشانی‌های IP یا بازه CIDR سرورتان محدود کنید و تاریخ انقضا بگذارید.
  • صورت‌حساب، اعضا، تنظیمات و حذف فضای کاری هرگز با کلید API در دسترس نیستند.

درخواست و پاسخ

  • نشانی پایه: https://pooshe.cloud/api/v1؛ فقط HTTPS.
  • بدنه‌ها JSON با UTF-8 (به‌جز بایت‌های فایل که application/octet-stream است).
  • شناسه‌ها رشته‌های مات (opaque) تا ۴۰ نویسه‌اند؛ ساختارشان را فرض نکنید.
  • زمان‌ها ISO 8601 به UTC؛ مبلغ‌ها به ریال و به‌صورت رشته عددی (مثل "5000000") تا دقت از دست نرود.
  • پاسخ‌ها ممکن است فیلد تازه بگیرند؛ فیلدهای ناشناخته را نادیده بگیرید.
  • هر پاسخ سرآیند X-Request-Id دارد. اگر خودتان یک شناسه معتبر (۸ تا ۱۲۸ نویسه از A-Z a-z 0-9 . _ : -) بفرستید، همان برمی‌گردد و در لاگ‌های ما هم ثبت است.

خطاها

خطاها در قالب استاندارد Problem Details (RFC 9457) و با Content-Type: application/problem+json برمی‌گردند. روی code تصمیم بگیرید (ثابت می‌ماند)؛ title برای نمایش به کاربر است و به‌طور پیش‌فرض فارسی است (با Accept-Language: en انگلیسی).

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json; charset=utf-8
X-Request-Id: 937b3263-b668-48fc-bc9d-1b7134cb90ec

{
  "type": "https://pooshe.cloud/developers/errors#validation_failed",
  "title": "ورودی معتبر نیست.",
  "status": 422,
  "code": "validation_failed",
  "requestId": "937b3263-b668-48fc-bc9d-1b7134cb90ec",
  "error": "validation_failed",
  "details": { "fields": ["name"] }
}
وضعیت‌های HTTP
400درخواست بدشکل (JSON نامعتبر، cursor نامعتبر)
401کلید نیست، نامعتبر، لغوشده یا منقضی است
403دامنه کلید کافی نیست، IP مجاز نیست، یا نقش عضو اجازه نمی‌دهد
404نیست یا به آن دسترسی ندارید (عمداً یکسان)
409تعارض: نام تکراری، وضعیت نهایی، یا درخواست هم‌کلید هنوز در جریان است
413 / 415فایل بزرگ‌تر از سقف یا نوع پشتیبانی‌نشده
402سقف پلن پر شده است (quota_exceeded؛ details.metric می‌گوید کدام سقف)
410آپلود چندبخشی منقضی شده است
422ورودی نامعتبر (details.fields فیلدها را نام می‌برد)
429از سقف نرخ گذشتید؛ پس از Retry-After دوباره
5xxخطای موقت سرور؛ با فاصله دوباره امتحان کنید

فهرست کامل کدهای خطا

صفحه‌بندی

فهرست‌های بلند با cursor صفحه‌بندی می‌شوند: پاسخ nextCursor دارد؛ آن را به‌عنوان ?cursor= بفرستید تا صفحه بعد بیاید. وقتی null شد، به انتها رسیده‌اید. اندازه صفحه با ?limit= (سقف هر مسیر در مرجع آمده). cursor مات است و فقط برای همان فهرست معتبر است.

for await (const file of pooshe.files.iterate(folderId)) {
  console.log(file.fileName, file.sizeBytes);
}

محدودیت نرخ

هر کلید ۱۲۰ درخواست در هر ۶۰ ثانیه. هر پاسخ (موفق یا خطا) این سرآیندها را دارد:

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 42        # ثانیه تا پنجره بعد

با پاسخ 429 سرآیند Retry-After هم می‌آید؛ همان‌قدر صبر کنید. SDK این کار را خودکار انجام می‌دهد.

تکرار امن درخواست (Idempotency-Key)

اگر اتصال وسط یک POST قطع شود، نمی‌دانید کار انجام شده یا نه. با سرآیند Idempotency-Key (یک UUID تازه برای هر کار) می‌توانید بی‌خطر دوباره بفرستید:

  • همان کلید و همان درخواست ← همان پاسخ اول، با سرآیند Idempotent-Replayed: true؛ کار دوباره انجام نمی‌شود.
  • همان کلید با بدنه دیگر ← 422 idempotency_key_reused. وقتی اولی هنوز در جریان است ← 409 idempotency_in_progress.
  • نتیجه ۲۴ ساعت نگه داشته می‌شود. خطاها و پاسخ‌های 5xx نگه داشته نمی‌شوند تا بتوانید با همان کلید دوباره امتحان کنید.
  • ارسال بخش‌های فایل (PUT) خودش تکرارپذیر است و کلید لازم ندارد.

آپلود فایل

دو راه، بسته به اندازه فایل و پایداری شبکه (سقف هر فایل در این سرور: ۵۰ مگابایت):

یک‌درخواستی

  1. POST /uploads → versionId
  2. PUT /uploads/{versionId}/content
  3. POST /uploads/{versionId}/finalize

چندبخشی و قابل ادامه

  1. POST /upload-sessions → partSize, totalParts
  2. PUT /upload-sessions/{id}/parts/{n} (any order, parallel)
  3. GET /upload-sessions/{id} → receivedParts (resume)
  4. POST /upload-sessions/{id}/complete

پس از نهایی‌سازی، فایل بررسی ویروس می‌شود و چند ثانیه بعد ready است. تا آن موقع لینک نمی‌گیرد. وضعیت را با GET /versions/{id} بپرسید یا منتظر وب‌هوک document.ready بمانید. فایل رد‌شده (ویروس یا نوع ناسازگار) وضعیت rejected می‌گیرد. اثر انگشت SHA-256 هر نسخه در GET /documents/{id} هست تا درستی آپلود را بسنجید.

وب‌هوک‌ها

در پنل (تنظیمات ← پیشرفته ← API و وب‌هوک) یک نشانی HTTPS عمومی و رویدادها را انتخاب کنید؛ رمز whsec_… فقط یک بار نمایش داده می‌شود. هر رویداد با POST و بدنه JSON فرستاده می‌شود:

POST /your/webhook
Content-Type: application/json
X-Pooshe-Event: document.ready
X-Pooshe-Delivery: k3lssq8mdmgeh0yg06p5hutz
X-Pooshe-Signature: t=1792364460,v1=5f2b…(HMAC-SHA256 hex)

{"id":"k3lssq8mdmgeh0yg06p5hutz","type":"document.ready","createdAt":"2026-10-19T08:30:00.000Z",
 "data":{"documentId":"…","versionId":"…","versionNumber":1,"pageCount":12,"current":true}}
رویدادهای وب‌هوک
document.readyفایل بررسی ویروس شد و آماده است (برای هر نسخه)
link.createdلینک اشتراک تازه ساخته شد
view.openedگیرنده برای اولین بار لینک را باز کرد (بازدید ربات‌ها نه)
cta.responseبیننده درخواست تماس، جلسه، سؤال یا پذیرش ثبت کرد
lead.hotمخاطبی به‌خاطر تعامل اخیر «داغ» شد
contact.createdمخاطب تازه ساخته شد
pingدکمه «ارسال آزمایشی» در پنل

بررسی امضا

امضا = HMAC-SHA256 با رمز وب‌هوک روی "<t>.<بدنه خام>". حتماً روی بدنه خام (پیش از پارس JSON) بررسی کنید، مقایسه را زمان‌ثابت انجام دهید و تحویل‌های قدیمی‌تر از ۵ دقیقه را رد کنید.

import express from 'express';
import { verifyWebhook } from '@pooshe/sdk';

const app = express();
// بدنه خام لازم است؛ نه JSON پارس‌شده
app.post('/pooshe/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  try {
    const event = await verifyWebhook({
      payload: req.body,
      signature: req.header('X-Pooshe-Signature'),
      secret: process.env.POOSHE_WEBHOOK_SECRET!, // whsec_…
    });
    if (await alreadyHandled(event.id)) return res.sendStatus(200); // تحویل تکراری
    await handle(event);
    res.sendStatus(200);
  } catch {
    res.sendStatus(400);
  }
});
  • ظرف ۱۰ ثانیه با 2xx پاسخ دهید و کار سنگین را در صف خودتان انجام دهید.
  • پاسخ غیر 2xx یا قطع اتصال تا چند بار با فاصله‌ی رو به افزایش دوباره فرستاده می‌شود؛ پس از ۲۰ شکست پیاپی، نشانی غیرفعال می‌شود.
  • یک رویداد ممکن است بیش از یک بار برسد: با id آن تکراری‌ها را کنار بگذارید.
  • فقط به نشانی‌های HTTPS عمومی فرستاده می‌شود (نه شبکه داخلی) و ریدایرکت دنبال نمی‌شود.

SDK تایپ‌اسکریپت و جاوااسکریپت

بدون وابستگی و با مجوز متن‌باز MIT؛ روی Node.js 18+، Deno، Bun و محیط‌های edge اجرا می‌شود و تایپ‌ها را همراه دارد.

# فایل ZIP را از همین صفحه دریافت و باز کنید، سپس:
npm install ./pooshe-sdk
  • تلاش دوباره خودکار برای قطع شبکه، 429 و 5xx با رعایت Retry-After
  • Idempotency-Key خودکار برای همه نوشتن‌ها، یکسان در همه تلاش‌ها
  • آپلود چندبخشی موازی، تکرار فقط بخش ناموفق، ادامه پس از قطع برنامه، گزارش پیشرفت
  • پیمایش صفحه‌ها با for await، خطای PoosheError با code و requestId، و verifyWebhook

زبان دیگری دارید؟ از مستند OpenAPI 3.1 با ابزارهایی مثل openapi-generator کلاینت بسازید.

نسخه‌بندی و تغییرات

/api/v1 پایدار است: فقط تغییرهای افزایشی (مسیر، فیلد یا رویداد تازه) در آن انجام می‌شود. تغییر ناسازگار فقط در نسخه بعد (/api/v2) می‌آید و v1 پیش از کنار رفتن با اطلاع قبلی مدتی کنارش می‌ماند.

۱۴۰۵/۰۷/۲۷

  • فایل‌ها، پوشه‌ها، آپلود (یک‌درخواستی و چندبخشی)، نسخه‌ها و دانلود با کلید API (دامنه files).
  • خطاها در قالب استاندارد problem+json (RFC 9457) با requestId؛ فیلدهای قبلی error و details حفظ شده‌اند.
  • X-Request-Id دلخواه شما در پاسخ برمی‌گردد؛ سرآیندهای X-RateLimit روی پاسخ‌های خطا هم هستند.
  • GET /api/v1/key، مستند OpenAPI 3.1 تازه با شِمای پاسخ‌ها، و SDK تایپ‌اسکریپت ۱٫۰.
  • وب‌هوک‌ها سرآیندهای X-Pooshe-* هم می‌فرستند (X-Sanad-* همچنان فرستاده می‌شود).
  • رفع اشکال: PATCH /links/{id} با بدنه ناقص، تنظیم‌های نفرستاده را به پیش‌فرض برمی‌گرداند؛ اکنون فقط فیلدهای فرستاده تغییر می‌کنند.

امنیت و بهترین روش‌ها

  • کلید API را فقط روی سرور نگه دارید؛ هرگز در مرورگر، اپ موبایل یا مخزن کد نه.
  • برای هر یکپارچه‌سازی کلید جدا با کمترین دامنه لازم بسازید؛ اگر فقط می‌خوانید، write ندهید.
  • کلید را به IP سرور خودتان محدود کنید و برایش تاریخ انقضا بگذارید؛ کلیدها را دوره‌ای عوض کنید.
  • اگر کلید لو رفت، همان لحظه از پنل لغوش کنید؛ همه درخواست‌های بعدی رد می‌شوند.
  • امضای هر وب‌هوک را بررسی کنید و نشانی لینک‌ها را مثل رمز نگه دارید: هرکس لینک را داشته باشد، طبق تنظیماتش می‌تواند بازش کند.