Skip to content

Quick Start ​

Here we'll send your first Telegram message through Zate, from scratch. It takes about 5 minutes, not even long enough for a serving of sate to go cold.

What You Need ​

  • A phone with an active Telegram account. If the account uses two-step verification, have the password ready too.
  • A terminal with curl. jq makes it even nicer.
  • Or Node.js 18+, if you'd rather jump straight to the full script below.

Every request on this page goes to the base URL:

text
https://api-zate.azickri.com

Create a Session ​

Call Create Session. No headers or body needed.

bash
curl -X POST "https://api-zate.azickri.com/session"

The response looks like this:

json
{
  "id": "68b3f0a2c1d4e5f6a7b8c9d0",
  "sessionId": "0b2f7059-8a90-4f6d-8684-b0e1ce6f0310"
}

Keep both values: they become the id and session-id headers on every request after this. To make life easier, put them in terminal variables:

bash
export ZATE_ID="68b3f0a2c1d4e5f6a7b8c9d0"
export ZATE_SESSION_ID="0b2f7059-8a90-4f6d-8684-b0e1ce6f0310"

Don't wait too long

You have 3 minutes to scan the QR code. After that the session is deleted automatically and you'll need a new one. So get your phone ready now.

Get the QR Code ​

The QR code is generated in the background, so wait 2–3 seconds, then call Get Session:

bash
curl "https://api-zate.azickri.com/session" \
  -H "id: $ZATE_ID" \
  -H "session-id: $ZATE_SESSION_ID"
json
{
  "id": "68b3f0a2c1d4e5f6a7b8c9d0",
  "generatedId": "",
  "name": "",
  "username": "",
  "phone": "",
  "sessionId": "0b2f7059-8a90-4f6d-8684-b0e1ce6f0310",
  "isConnected": false,
  "qrcode": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAAB...",
  "isPasswordRequired": false,
  "passwordHint": "",
  "picture": "",
  "webhook": { "url": "", "token": "" }
}

The qrcode field is a base64 PNG image (without a data: prefix). The easiest ways to view it:

bash
curl -s "https://api-zate.azickri.com/session" \
  -H "id: $ZATE_ID" \
  -H "session-id: $ZATE_SESSION_ID" \
  | jq -r '.qrcode' | base64 -d > qr.png

# Open qr.png in your favorite image viewer
html
<!-- Add the data URL prefix, then show it as an image -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAAB..." />

The QR changes every 30 seconds

Telegram only hands out short-lived login tokens, so Zate makes a new QR roughly every 30 seconds. If qrcode is still empty, wait a moment and call again. Always use the newest QR.

Scan It from Telegram ​

  1. Open Telegram on your phone.
  2. Go to Settings → Devices.
  3. Tap Link Desktop Device, then scan the QR code.

Telegram will send a "new login" notification to your account. That's expected: Zate just logged in as a new device.

Then call Get Session again. Once connected, isConnected becomes true, and name, username, phone, and picture are filled in:

json
{
  "id": "68b3f0a2c1d4e5f6a7b8c9d0",
  "generatedId": "123456789",
  "name": "Cak Zate",
  "username": "cakzate",
  "phone": "6281234567890",
  "sessionId": "0b2f7059-8a90-4f6d-8684-b0e1ce6f0310",
  "isConnected": true,
  "qrcode": "",
  "isPasswordRequired": false,
  "passwordHint": "",
  "picture": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...",
  "webhook": { "url": "", "token": "" }
}

Does your account use two-step verification?

After the scan, qrcode turns empty and isPasswordRequired becomes true (your password hint is in passwordHint). Send the password with Submit Password:

bash
curl -X POST "https://api-zate.azickri.com/session/password" \
  -H "id: $ZATE_ID" \
  -H "session-id: $ZATE_SESSION_ID" \
  -H "Content-Type: application/json" \
  -d '{"password":"your-cloud-password"}'

If it's correct, isConnected becomes true right away.

Send Your First Message ​

The moment you've been waiting for. Replace @target_username with a Telegram username, then call Send Message:

bash
curl -X POST "https://api-zate.azickri.com/message" \
  -H "id: $ZATE_ID" \
  -H "session-id: $ZATE_SESSION_ID" \
  -H "Content-Type: application/json" \
  -d '{"username":"@target_username","type":"text","text":"Hello from Zate! 🍢"}'
json
{
  "messageId": "1024"
}

No one to test with?

Use your own username. The message lands in your Saved Messages, safe and bothering nobody.

Check Telegram. If the message is there, congratulations, you're officially a Zate regular! 🎉

Full Version with Node.js ​

Don't feel like copy-pasting each step? This script runs all of the steps above in one go: it creates a session, saves the QR to qr.png whenever it changes, asks for the password if the account uses two-step verification, waits until you're connected, then sends a message.

js
// quick-start.mjs
// Run: node quick-start.mjs @target_username
import { writeFile } from 'node:fs/promises';
import { createInterface } from 'node:readline/promises';

const BASE_URL = 'https://api-zate.azickri.com';
const username = process.argv[2];
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function zate(method, path, { headers = {}, body } = {}) {
  const response = await fetch(BASE_URL + path, {
    method,
    headers: { 'Content-Type': 'application/json', ...headers },
    body: body ? JSON.stringify(body) : undefined,
  });

  const data = await response.json();
  if (!response.ok) throw new Error(`${data.statusCode}: ${data.message}`);
  return data;
}

// 1. Create a session
const { id, sessionId } = await zate('POST', '/session');
const auth = { 'id': id, 'session-id': sessionId };
console.log('Session created:', auth);

// 2 & 3. Save the QR to qr.png, wait for the scan, ask for the password if needed
let lastQrcode = '';
while (true) {
  const session = await zate('GET', '/session', { headers: auth });

  if (session.isConnected) {
    console.log(`Connected as ${session.name}!`);
    break;
  }

  if (session.isPasswordRequired) {
    const rl = createInterface({ input: process.stdin, output: process.stdout });
    const hint = session.passwordHint ? ` (hint: ${session.passwordHint})` : '';
    const password = await rl.question(`Two-step verification password${hint}: `);
    rl.close();

    try {
      await zate('POST', '/session/password', { headers: auth, body: { password } });
    } catch (error) {
      console.log(error.message); // 400: invalid password, try again
    }
    continue;
  }

  if (session.qrcode && session.qrcode !== lastQrcode) {
    lastQrcode = session.qrcode;
    await writeFile('qr.png', Buffer.from(session.qrcode, 'base64'));
    console.log('New QR saved to qr.png, scan it from Telegram!');
  }

  await sleep(3000);
}

// 4. Send the first message
const { messageId } = await zate('POST', '/message', {
  headers: auth,
  body: { username, type: 'text', text: 'Hello from Zate! 🍢' },
});

console.log('Message sent:', messageId);

If the script stops with 404: session not found while waiting, the QR expired before you scanned it. Just run it again and scan a bit faster. 😄

What's Next? ​