# توسعه‌دهندگان پیکو

> ساخت ربات برای پیام‌رسان پیکو

Online: https://docs.picogram.ir/developers/fa/

## ربات پیکو چیست؟

ربات یک برنامه‌ی کوچک است که در پیکو مثل یک مخاطب عادی با آدم‌ها صحبت می‌کند. شما آن را با هر زبان برنامه‌نویسی می‌نویسید، هر جا خواستید اجرا می‌کنید و ربات از راه یک API ساده روی HTTPS با پیکو حرف می‌زند.

Bot API پیکو همان شکل و قالب تلگرام را دارد؛ پس اگر قبلاً ربات تلگرام نوشته‌اید، بیشترش را از قبل بلدید. 🎉

🏠 کد کجا اجرا می‌شود؟ روی کامپیوتر خودتان، یک سرور، VPS یا تابع ابری. پیکو پیام‌ها را به برنامه‌ی شما می‌رساند و پاسخ آن را برمی‌گرداند. پیکو (فعلاً) کد شما را اجرا نمی‌کند.

## شروع سریع

ربات را بسازید. در پیکو @botfather را باز کنید و /newbot را بفرستید. یک نام و یک نام کاربری که به bot ختم شود انتخاب کنید.

توکن را کپی کنید. بات‌فادر توکنی شبیه 123456:AbCdEf-your-token می‌فرستد. برای کپی روی آن بزنید. هر وقت خواستید دوباره می‌توانید ببینیدش: /mybots ← ربات شما ← 🔑 توکن API.

به رباتتان سلام کنید. آن را باز کنید و Start را بزنید. ربات‌ها هرگز نمی‌توانند به کسی که اول به آن‌ها پیام نداده، پیام بدهند.

یک برنامه اجرا کنید. یکی از مثال‌های زیر را بردارید، توکن را بگذارید و به رباتتان پیام بدهید. 🎈

curlPythonNode.jsPHPGo

Copycurl "https://picogram.ir/bot123456:AbCdEf-your-token/getMe"

curl -X POST "https://picogram.ir/bot123456:AbCdEf-your-token/sendMessage" \
  -H "content-type: application/json" \
  -d '{"chat_id": 42, "text": "Hello from my bot 👋"}'
curl

Copyimport requests

TOKEN = "123456:AbCdEf-your-token"
API = f"https://picogram.ir/bot{TOKEN}"
offset = 0

while True:
    r = requests.get(f"{API}/getUpdates", params={"offset": offset, "timeout": 30}, timeout=40).json()
    for u in r["result"]:
        offset = u["update_id"] + 1
        m = u.get("message")
        if m and m.get("text"):
            requests.post(f"{API}/sendMessage", json={"chat_id": m["chat"]["id"], "text": f"You said: {m['text']}"})
Python

Copyconst TOKEN = "123456:AbCdEf-your-token";
const API = `https://picogram.ir/bot${TOKEN}`;
let offset = 0;

for (;;) {
  const r = await (await fetch(`${API}/getUpdates?offset=${offset}&timeout=30`)).json();
  for (const u of r.result) {
    offset = u.update_id + 1;
    const m = u.message;
    if (m?.text) {
      await fetch(`${API}/sendMessage`, {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ chat_id: m.chat.id, text: `You said: ${m.text}` }),
      });
    }
  }
}
Node.js

Copy<?php
$api = "https://picogram.ir/bot" . getenv("PICO_TOKEN");
$offset = 0;

while (true) {
    $res = json_decode(file_get_contents("$api/getUpdates?offset=$offset&timeout=30"), true);
    foreach ($res["result"] as $u) {
        $offset = $u["update_id"] + 1;
        if (!empty($u["message"]["text"])) {
            $m = $u["message"];
            file_get_contents("$api/sendMessage?" . http_build_query([
                "chat_id" => $m["chat"]["id"], "text" => "You said: " . $m["text"],
            ]));
        }
    }
}
PHP

Copypackage main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

const api = "https://picogram.ir/bot123456:AbCdEf-your-token"

func main() {
	offset := 0
	for {
		resp, err := http.Get(fmt.Sprintf("%s/getUpdates?offset=%d&timeout=30", api, offset))
		if err != nil { continue }
		var out struct {
			Result []struct {
				UpdateID int `json:"update_id"`
				Message  *struct {
					Text string `json:"text"`
					Chat struct{ ID int `json:"id"` } `json:"chat"`
				} `json:"message"`
			} `json:"result"`
		}
		json.NewDecoder(resp.Body).Decode(&out)
		resp.Body.Close()
		for _, u := range out.Result {
			offset = u.UpdateID + 1
			if u.Message != nil && u.Message.Text != "" {
				http.PostForm(api+"/sendMessage", url.Values{
					"chat_id": {fmt.Sprint(u.Message.Chat.ID)}, "text": {"You said: " + strings.TrimSpace(u.Message.Text)}})
			}
		}
	}
}
Go

🔑 توکن مثل رمز عبور است. هرگز آن را در مخزن عمومی یا صفحه‌ی وب نگذارید.

## چطور وصل شویم

همه‌ی درخواست‌ها به این نشانی می‌روند:

Copyhttps://picogram.ir/bot<TOKEN>/<METHOD>
URL

🔒 فقط HTTPS.

📨 پارامترها را به‌صورت query string، بدنه‌ی JSON (content-type: application/json) یا هر دو بفرستید. هم GET و هم POST کار می‌کند.

📦 پاسخ همیشه JSON است: در حالت موفق {"ok": true, "result": …} و در حالت خطا {"ok": false, "error_code": 400, "description": "…"}.

🐢 سقف درخواست: ۶۰۰ درخواست در دقیقه برای هر آدرس IP.

کتابخانه‌های تلگرام

بیشتر کتابخانه‌های ربات تلگرام اجازه می‌دهند آدرس API را عوض کنید. آن‌ها را به پیکو وصل کنید تا برای همه‌ی متدهای این صفحه کار کنند. متدهایی که پیکو هنوز ندارد خطا برمی‌گردانند.

Copy# python-telegram-bot
Application.builder().token(TOKEN).base_url("https://picogram.ir/bot").build()

# aiogram 3
AiohttpSession(api=TelegramAPIServer.from_base("https://picogram.ir"))

# grammY
new Bot(TOKEN, { client: { apiRoot: "https://picogram.ir" } })

# Telegraf
new Telegraf(TOKEN, { telegram: { apiRoot: "https://picogram.ir" } })

# node-telegram-bot-api
new TelegramBot(TOKEN, { polling: true, baseApiUrl: "https://picogram.ir" })
Libraries

## زبان‌ها و قالب‌ها

برای پیکو فرقی ندارد ربات را با چه زبانی بنویسید. اگر زبان شما بتواند درخواست HTTPS بفرستد و JSON بخواند، کار می‌کند: پایتون، جاوااسکریپت / تایپ‌اسکریپت (Node، Deno، Bun)، PHP، Go، جاوا، کاتلین، C#، Rust، روبی، دارت، سوئیفت، اسکریپت شل… 🌍

 | پذیرفته می‌شود | 
📡 انتقال | HTTPS (‏TLS 1.2 به بالا) | 
📝 درخواست | query string، بدنه‌ی JSON (application/json) یا هر دو | 
📤 پاسخ | JSON با UTF-8 | 
🔤 متن | UTF-8، ۱ تا ۴۰۹۶ نویسه در هر پیام | 
🔁 دریافت پیام | long polling با getUpdates یا وب‌هوک |

## متدها

متد | پارامترها | کار | 
getMe | — | شناسه، نام و نام کاربری ربات شما. | 
getUpdates | offset، timeout (۰ تا ۵۰ ثانیه)، limit (۱ تا ۱۰۰) | long polling. با offset = آخرین update_id + 1 اعلام کنید کدام‌ها را انجام داده‌اید. | 
sendMessage | chat_id، text، parse_mode، reply_to_message_id، reply_markup | ارسال پیام متنی. | 
editMessageText | chat_id، message_id، text، parse_mode، reply_markup | ویرایش پیامی که ربات فرستاده. | 
deleteMessage | chat_id، message_id | حذف پیامی که ربات فرستاده. | 
answerCallbackQuery | callback_query_id | به پیکو می‌گوید ضربه‌ی دکمه را انجام داده‌اید. | 
sendChatAction | chat_id، action | برای اینکه کدهای موجود کار کنند پذیرفته می‌شود. | 
setMyCommands / getMyCommands | commands: فهرست JSON از {command, description} (تا ۱۰۰ مورد) | منوی دستورهای ربات. دستورها حروف کوچک انگلیسی، عدد و آندرلاین‌اند. | 
getChat | chat_id | اطلاعات پایه‌ی یک گفتگو. | 
setWebhook / deleteWebhook / getWebhookInfo | url، secret_token | دریافت به‌روزرسانی با وب‌هوک به‌جای polling. | 

🧭 chat_id همان عددی است که در message.chat.id هر به‌روزرسانی می‌بینید.

## عکس، ویدئو و فایل

ربات شما می‌تواند هر چیزی را که آدم‌ها در پیکو می‌فرستند بفرستد و دریافت هم بکند.

متد | پارامتر فایل | نمایش | 
sendPhoto | photo | عکس | 
sendVideo | video | ویدئوی قابل پخش داخل گفتگو | 
sendAnimation | animation | ویدئوی تکرارشونده یا GIF | 
sendAudio | audio | فایل صوتی | 
sendVoice | voice | پیام صوتی با شکل موج | 
sendDocument | document | هر فایل دیگر | 
sendLocation، sendContact، sendDice | — | پیوند نقشه، کارت مخاطب، تاس‌انداختن 🎲 | 

همه‌ی این‌ها chat_id، caption (تا ۱۰۲۴ نویسه)، parse_mode، reply_to_message_id و reply_markup را هم می‌گیرند. برای ویدئو و صدا می‌توانید duration، width و height هم بدهید.

خود فایل را سه‌ جور می‌توان داد:

Copy# 1) upload a file from your computer (multipart/form-data)
curl -F chat_id=42 -F caption="Look 👀" -F photo=@cat.jpg "https://picogram.ir/bot123456:AbCdEf-your-token/sendPhoto"

# 2) send a file Pico already has (a file_id from an update or an earlier message)
curl "https://picogram.ir/bot123456:AbCdEf-your-token/sendDocument" -d chat_id=42 -d document=<FILE_ID>

# 3) let Pico download a public https link for you
curl "https://picogram.ir/bot123456:AbCdEf-your-token/sendVideo" -d chat_id=42 --data-urlencode "video=https://example.com/clip.mp4"

# receive: getFile gives a path, then download it
curl "https://picogram.ir/bot123456:AbCdEf-your-token/getFile?file_id=<FILE_ID>"
curl -O "https://picogram.ir/file/bot123456:AbCdEf-your-token/files/<FILE_ID>"
curl

📤 آپلود با multipart/form-data (در هر درخواست یک فایل).

🆔 یک file_id که پیکو به شما داده، برای فرستادن دوباره‌ی همان فایل بدون آپلود.

🔗 یک لینک https عمومی: پیکو خودش آن را دانلود می‌کند (تا ۵۰ مگابایت، فقط آدرس‌های عمومی).

دریافت فایل

وقتی کسی عکس، ویدئو، پیام صوتی یا فایلی برای ربات شما می‌فرستد، به‌روزرسانی فیلد متناظر (photo، video، voice، document)، یک file_id و caption را دارد.

Copy{
  "update_id": 120,
  "message": {
    "message_id": 940,
    "from": { "id": 7, "is_bot": false, "first_name": "Sara" },
    "chat": { "id": 42, "type": "private" },
    "caption": "my cat",
    "photo": [ { "file_id": "k2s9…", "width": 1280, "height": 960, "file_size": 183412 } ]
  }
}
JSON

getFile را صدا بزنید تا یک file_path بگیرید، بعد https://picogram.ir/file/bot<TOKEN>/<file_path> را دانلود کنید. بزرگ‌ترین فایل ۲۰۰ مگابایت است (۵۰ مگابایت برای آپلود و لینک از سمت ربات).

فوروارد، کپی و ویرایش

forwardMessage و copyMessage (‏chat_id، from_chat_id، message_id)، editMessageCaption، editMessageReplyMarkup، pinChatMessage و unpinChatMessage.

## گروه، کانال و متدهای مدیریتی

ربات خود را به یک گروه یا کانال اضافه کنید، با دسترسی‌های لازم ادمینش کنید تا بتواند گفتگو را مدیریت کند.

متد | دسترسی لازم | کار | 
getChatMember | — | وضعیت یک نفر: creator، administrator، member، left یا kicked همراه دسترسی‌هایش. | 
getChatAdministrators | — | مالک و همه‌ی ادمین‌ها. | 
getChatMemberCount | — | تعداد اعضا. | 
banChatMember / unbanChatMember | ban | حذف و مسدودکردن بازگشت یک نفر، یا اجازه‌ی برگشتش. | 
setChatTitle / setChatDescription | info | تغییر نام یا توضیح. | 
pinChatMessage / unpinChatMessage | pin | سنجاق‌کردن یا برداشتن سنجاق پیام. | 
leaveChat | — | ربات خارج می‌شود. | 
promoteChatMember | admins | کسی را با can_change_info، can_post_messages، can_edit_messages، can_delete_messages، can_restrict_members، can_invite_users، can_pin_messages و can_promote_members ادمین می‌کند (هرگز بیشتر از دسترسی‌های خود ربات). | 
setChatPermissions | ban | تعیین اینکه اعضای عادی گروه چه کارهایی بکنند. | 
exportChatInviteLink / createChatInviteLink / revokeChatInviteLink | invite | گرفتن یا بازنشانی پیوند دعوت. | 
setChatPhoto / deleteChatPhoto | info | تغییر تصویر. | 
unpinAllChatMessages | pin | برداشتن همه‌ی سنجاق‌ها. | 
deleteMessages، forwardMessages، copyMessages، sendMediaGroup | — | چند پیام یکجا؛ آلبوم تا ۱۰ عکس، ویدئو، فایل صوتی یا سند. | 

دسترسی‌های ادمین

مالک و ادمین‌ها دقیقاً همان دسترسی‌هایی را که لازم است به افراد (و ربات‌ها) می‌دهند: تغییر اطلاعات، ارسال پیام (کانال)، ویرایش و حذف پیام، مسدودکردن افراد، دعوت افراد، سنجاق‌کردن پیام و افزودن ادمین جدید. مالک همچنین می‌تواند گفتگو را به شخص دیگری واگذار کند و تعیین کند اعضای عادی یک گروه چه کارهایی بتوانند بکنند (ارسال پیام، ارسال رسانه، افزودن افراد، سنجاق و تغییر اطلاعات).

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

setMyName، getMyName، setMyDescription، getMyDescription. تصویر ربات را در @botfather عوض کنید: /mybots ← ربات شما ← 📷 ویرایش تصویر.

پاسخ به دکمه‌ها

answerCallbackQuery با text یک پیام کوتاه به کسی که روی دکمه زده نشان می‌دهد.

به‌روزرسانی عضویت

وقتی ربات شما به یک گروه یا کانال اضافه یا از آن حذف می‌شود، یک به‌روزرسانی my_chat_member با status قبلی و جدید (member، left یا kicked) می‌گیرد.

## به‌روزرسانی‌ها: ربات چه دریافت می‌کند

هر مورد از getUpdates (یا هر فراخوانی وب‌هوک) یک update_id دارد و یکی از دو چیز را:

💬 یک پیام
Copy{
  "update_id": 118,
  "message": {
    "message_id": 931,
    "from": { "id": 7, "is_bot": false, "first_name": "Sara", "username": "sara" },
    "date": 1767225600,
    "text": "hello",
    "chat": { "id": 42, "type": "private" }
  }
}
JSON

text متن ساده است. اگر کاربر قالب‌بندی کرده باشد، formatted_text هم متن اصلی را همراه نمادهای قالب‌بندی پیکو دارد.

👆 ضربه روی دکمه
Copy{
  "update_id": 119,
  "callback_query": {
    "id": "931.1767225700000",
    "from": { "id": 7, "is_bot": false, "first_name": "Sara", "username": "sara" },
    "data": "yes",
    "message": { "message_id": 931, "chat": { "id": 42, "type": "private" }, "text": "Pick one" }
  }
}
JSON

در گروه‌ها و کانال‌ها ربات فقط دستورها (/start)، پیام‌هایی که به آن اشاره دارند (@yourbot) و پاسخ به پیام‌های خودش را می‌بیند.

⏳ به‌روزرسانی‌هایی که تأیید نکنید ۲۴ ساعت نگه داشته می‌شوند.

## قالب‌بندی متن

به sendMessage و editMessageText پارامتر parse_mode بدهید: HTML، MarkdownV2 یا Markdown، دقیقاً مثل تلگرام. بدون آن متن همان‌طور که نوشته‌اید فرستاده می‌شود.

HTML
Copy<b>bold</b> <i>italic</i> <u>underline</u> <s>strike</s> <tg-spoiler>spoiler</tg-spoiler>
<a href="https://picogram.ir">link</a> <code>inline code</code>
<pre><code class="language-python">print("hi")</code></pre>
<blockquote>quote</blockquote>
HTML

MarkdownV2
Copy*bold* _italic_ __underline__ ~strike~ ||spoiler||
[link](https://picogram.ir) `inline code`
```python
print("hi")
```
>quote  (escape these with a backslash: _ * [ ] ( ) ~ ` > # + - = | { } . !)
MarkdownV2

پیکو پررنگ، کج، زیرخط، خط‌خورده، اسپویلر، کد درون‌خطی، بلوک کد با نام زبان، پیوند و نقل‌قول (حتی جمع‌شونده با <blockquote expandable>) را پشتیبانی می‌کند. اشاره (@name)، هشتگ، پیوند، ایمیل و /دستورها خودکار شناخته می‌شوند. اگر قالب‌بندی خراب باشد 400 can't parse entities می‌گیرید.

✨ کاربران هم می‌توانند پیام‌هایشان را قالب‌بندی کنند: متن را انتخاب کنند و دکمه‌ی T را بزنند، یا بنویسند **پررنگ** __کج__ ++زیرخط++ ~~خط‌خورده~~ ||اسپویلر||.

## دکمه‌ها (کیبورد درون‌خطی)

به پیام reply_markup بدهید تا زیر آن دکمه نمایش داده شود. هر دکمه یا callback_data دارد (با ضربه روی آن، ربات یک callback_query می‌گیرد) یا url (یک پیوند را باز می‌کند).

Copy{
  "chat_id": 42,
  "text": "Pick one 👇",
  "reply_markup": {
    "inline_keyboard": [
      [ { "text": "✅ Yes", "callback_data": "yes" }, { "text": "❌ No", "callback_data": "no" } ],
      [ { "text": "🌐 Website", "url": "https://example.com" } ]
    ]
  }
}
JSON

محدودیت | مقدار | 
ردیف‌ها | تا ۸ | 
دکمه در هر ردیف | تا ۸ | 
متن دکمه | ۱ تا ۶۴ نویسه | 
callback_data | تا ۶۴ نویسه | 
url | فقط پیوندهای http(s) | 

🎯 نکته‌ی طراحی: دو دکمه در هر ردیف روی گوشی زیباتر است. یک دکمه در ردیف را فقط برای برچسب‌های بلند استفاده کنید.
وقتی کسی روی دکمه می‌زند، answerCallbackQuery را صدا بزنید و بعد با editMessageText پیام را به‌روز کنید یا پیام تازه بفرستید.

کیبورد پاسخ

جز دکمه‌های زیر پیام، reply_markup می‌تواند کلیدهایی را بالای فیلد پیام نشان دهد. ضربه روی یک کلید، متن آن را مثل پیام عادی می‌فرستد.

Copy{ "keyboard": [[{"text":"یک"},{"text":"دو"}],[{"text":"انصراف"}]], "resize_keyboard": true, "one_time_keyboard": true, "input_field_placeholder": "انتخاب کنید…" }
JSON

one_time_keyboard: کلیدها بعد از یک ضربه پنهان می‌شوند (با دکمه‌ی کیبورد برمی‌گردند).

{"remove_keyboard": true}: کلیدها را برمی‌دارد.

{"force_reply": true}: فیلد پیام بلافاصله به پیام شما پاسخ می‌دهد.

## وب‌هوک

به‌جای polling، پیکو می‌تواند هر وقت اتفاقی افتاد سرور شما را صدا بزند.

Copycurl "https://picogram.ir/bot123456:AbCdEf-your-token/setWebhook" \
  --data-urlencode "url=https://bot.example.com/pico-hook" \
  --data-urlencode "secret_token=my_secret_123"
curl

🔒 آدرس باید https روی پورت ۴۴۳ یا ۸۴۴۳ باشد و به یک آدرس عمومی برسد.

🔑 اگر secret_token بگذارید، هر فراخوانی هدر X-Pico-Bot-Api-Secret-Token را دارد. آن را بررسی کنید.

📮 پیکو به‌روزرسانی را به‌صورت JSON در یک POST می‌فرستد. ظرف ۱۰ ثانیه با 2xx جواب بدهید.

🔁 ارسال ناموفق ۳ بار تلاش می‌شود (همین حالا، بعد از ۱٫۵ ثانیه، بعد از ۸ ثانیه). getWebhookInfo آخرین خطا را نشان می‌دهد.

⚠️ تا وقتی وب‌هوک تنظیم است، getUpdates خطای 409 Conflict می‌دهد. برای برگشت به polling، deleteWebhook را صدا بزنید.

## قوانین و محدودیت‌ها

موضوع | قانون | 
نام کاربری | به bot ختم شود، ۴ تا ۳۲ حرف انگلیسی، عدد یا آندرلاین، با حرف شروع شود. نام‌هایی که pico دارند فقط برای تیم پیکو هستند. | 
شروع گفتگو | ربات فقط به کسانی می‌تواند پیام بدهد که اول به آن پیام داده‌اند. | 
گروه و کانال | ربات دستورها، اشاره‌ها و پاسخ به خودش را می‌بیند. | 
رمزنگاری | گفتگو با ربات‌ها، گروه‌ها و کانال‌ها گفتگوی خصوصی حساب نمی‌شوند: هنگام انتقال و ذخیره محافظت می‌شوند. گفتگوی خصوصی بین دو نفر با کلیدهای وابسته به حساب‌هایشان رمزنگاری می‌شود. | 
اندازه‌ی پیام | ۱ تا ۴۰۹۶ نویسه. | 
نرخ درخواست | ۶۰۰ درخواست در دقیقه برای هر IP. | 
نگهداری به‌روزرسانی‌ها | ۲۴ ساعت. | 

🚧 هنوز موجود نیست

حالت inline (‏answerInlineQuery)، پرداخت، بازی، نظرسنجی، استیکر، sendVideoNote، دستورها به تفکیک زبان یا حوزه، و مینی‌اپ. نیازتان را از طریق @support در پیکو بگویید. 💙

## خطاها

کد | معنا | چه کنیم | 
401 | Unauthorized | توکن اشتباه است یا باطل شده. در بات‌فادر بررسی کنید. | 
400 | Bad Request | پارامتری ناقص یا نامعتبر است یا قالب‌بندی خوانده نشد. description را بخوانید. | 
403 | Forbidden | ربات در آن گفتگو نیست یا شخص اول به ربات پیام نداده. | 
404 | Not Found | این متد وجود ندارد (هنوز). | 
409 | Conflict | وب‌هوک تنظیم است. deleteWebhook را بزنید یا از وب‌هوک استفاده کنید. | 
429/5xx | کندتر / مشکل سرور | کمی صبر کنید و دوباره تلاش کنید. |
