شروع سریع
- در پنل، تنظیمات ← پیشرفته ← API و وبهوک یک کلید بسازید و فقط دامنههای لازم را بدهید (در پلنهای کسبوکار و تیم).
- کلید را فقط یک بار میبینید؛ آن را در متغیر محیطی سرورتان بگذارید، نه در کد.
- اولین درخواست را بفرستید: فایلی آپلود کنید و برایش لینک اشتراک بسازید.
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_… دارد. کلید بهجای عضوی که آن را ساخته عمل میکند و همیشه با نقش فعلی او: اگر عضو از تیم حذف شود یا نقشش محدود شود، کلید هم همان لحظه محدود میشود. هر کلید فقط به منابع فضای کاری خودش دسترسی دارد.
| دامنه | چه چیزی | مسیرها |
|---|---|---|
files:readfiles:write | فایلها، پوشهها، آپلود، نسخهها، دانلود و سطل زباله | /drive، /uploads، /upload-sessions، /documents، /versions |
sharing:readsharing:write | لینکهای اشتراک و آمار بازدید آنها | /links |
crm:readcrm:write | مخاطبان، شرکتها، سرنخها، پیگیریها، یادداشتها، فرصتها و پاسخ بینندگان | /contacts، /companies، /leads، /followups، /notes، /opportunities، /responses |
quotes:readquotes:write | کاتالوگ کالا و خدمات و پیشفاکتورها | /catalog، /quotes |
analytics:readanalytics: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"] }
}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) خودش تکرارپذیر است و کلید لازم ندارد.
آپلود فایل
دو راه، بسته به اندازه فایل و پایداری شبکه (سقف هر فایل در این سرور: ۵۰ مگابایت):
یکدرخواستی
- POST /uploads → versionId
- PUT /uploads/{versionId}/content
- POST /uploads/{versionId}/finalize
چندبخشی و قابل ادامه
- POST /upload-sessions → partSize, totalParts
- PUT /upload-sessions/{id}/parts/{n} (any order, parallel)
- GET /upload-sessions/{id} → receivedParts (resume)
- 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 سرور خودتان محدود کنید و برایش تاریخ انقضا بگذارید؛ کلیدها را دورهای عوض کنید.
- اگر کلید لو رفت، همان لحظه از پنل لغوش کنید؛ همه درخواستهای بعدی رد میشوند.
- امضای هر وبهوک را بررسی کنید و نشانی لینکها را مثل رمز نگه دارید: هرکس لینک را داشته باشد، طبق تنظیماتش میتواند بازش کند.


