SDSuryaDocs

Dokumentasi API SuryaDocs

Semua endpoint berada di bawah https://docs.suryacloud.my.id. Contoh ditulis dalam PHP native dengan cURL — tidak perlu framework, tidak perlu Composer, dan berjalan di shared hosting biasa.

Mulai cepat

  1. Daftar, lalu buat API key di dashboard.
  2. Isi saldo (atau pakai kuota gratis playground untuk mencoba).
  3. Kirim dokumen ke endpoint, simpan id pekerjaannya.
  4. Tunggu hasilnya — lewat polling atau webhook.

Autentikasi

Setiap permintaan ke /v1/* memerlukan API key rahasia Anda di header Authorization:

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx
Jaga kerahasiaannya. API key rahasia hanya boleh dipakai dari server Anda. Jangan pernah menaruhnya di HTML, JavaScript, atau aplikasi mobile — siapa pun yang melihatnya bisa memakai saldo Anda. Untuk kebutuhan di sisi browser, gunakan widget dengan kunci publik (pk_live_…).

Key hanya ditampilkan satu kali saat dibuat dan tidak disimpan dalam bentuk yang bisa kami tampilkan ulang. Kehilangan key berarti membuat yang baru dan mencabut yang lama.

Alur asinkron

Semua operasi bersifat asinkron. Permintaan Anda langsung dibalas 202 Accepted berisi id pekerjaan, dan pemrosesan berjalan di server kami.

Ini disengaja: mengonversi dokumen bisa memakan beberapa detik, dan menahan worker PHP-FPM hosting Anda selama itu adalah cara tercepat membuat seluruh situs ikut melambat saat permintaan menumpuk. Dengan pola ini, hosting Anda hanya mengirim dan menerima — tidak pernah menunggu.

{
  "id": "9f1c2e64-...",
  "type": "convert",
  "status": "queued",
  "resultUrl": null,
  "createdAt": "2026-08-20T09:12:44.000Z",
  "expiresAt": "2026-08-21T09:12:44.000Z"
}

Status berpindah queuedprocessingsucceeded atau failed. Ambil hasilnya lewat dua cara:

  • Polling — paling sederhana, tidak perlu URL publik.
  • Webhook — lebih hemat, kami yang menghubungi server Anda.

Convert — Office ke PDF

POST /v1/convert

Mengubah DOCX, DOC, ODT, XLSX, PPTX, atau RTF menjadi PDF menggunakan LibreOffice.

<?php
// Ubah DOCX menjadi PDF. Permintaan langsung kembali (202) —
// pemrosesan berjalan di server SuryaDocs, bukan di hosting Anda.
$ch = curl_init('https://docs.suryacloud.my.id/v1/convert');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . SURYADOCS_API_KEY],
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => [
        'file' => new CURLFile('/path/surat.docx'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

$jobId = $response['id'];   // simpan ini
// status: "queued" -> nanti jadi "succeeded"

Lalu tunggu dan unduh hasilnya:

<?php
// Cara paling sederhana: tanya statusnya sampai selesai.
// (Kalau server Anda bisa menerima webhook, itu lebih hemat — lihat bagian Webhook.)
function suryadocsTunggu(string $jobId, int $maksDetik = 60): array {
    $mulai = time();
    while (time() - $mulai < $maksDetik) {
        $ch = curl_init('https://docs.suryacloud.my.id/v1/jobs/' . $jobId);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . SURYADOCS_API_KEY],
        ]);
        $job = json_decode(curl_exec($ch), true);
        curl_close($ch);

        if ($job['status'] === 'succeeded') return $job;
        if ($job['status'] === 'failed')    throw new RuntimeException($job['error']);
        sleep(2);
    }
    throw new RuntimeException('waktu tunggu habis');
}

$job = suryadocsTunggu($jobId);
// Unduh hasilnya
file_put_contents('/path/surat.pdf', file_get_contents(
    $job['resultUrl'] . '?', false,
    stream_context_create(['http' => [
        'header' => 'Authorization: Bearer ' . SURYADOCS_API_KEY,
    ]])
));
FieldWajibKeterangan
fileya*Berkas dokumen (multipart)
sourceUrlya*Alternatif file: URL publik dokumen

*salah satu dari keduanya.

Arah sebaliknya (PDF → DOCX) tidak kami sediakan. Hasil konversinya tidak dapat diandalkan untuk dokumen yang sedikit saja kompleks, dan kami memilih tidak menjanjikan sesuatu yang akan mengecewakan di produksi.

Overlay — kop surat

POST /v1/overlay

Menempelkan gambar (kop surat, logo, stempel) di atas PDF yang sudah ada, presisi di sisi server — bukan bergantung pada pengaturan cetak peramban masing-masing pengguna.

<?php
// Tempel kop surat di atas PDF yang sudah ada.
$ch = curl_init('https://docs.suryacloud.my.id/v1/overlay');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . SURYADOCS_API_KEY],
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => [
        'file'     => new CURLFile('/path/surat.pdf'),
        'asset'    => new CURLFile('/path/kop-surat.png'),
        'position' => 'top-center',   // lihat tabel posisi di bawah
        'pages'    => 'all',          // all | first | last | "1,3,5"
    ],
]);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);
FieldDefaultKeterangan
filePDF dasar (wajib)
assetGambar PNG/JPG (wajib)
positiontop-centertop-left, top-center, top-right, middle-center, bottom-left, bottom-center, bottom-right
pagesallall, first, last, atau daftar seperti 1,3,5
widthlebar halamanLebar dalam poin (1 poin = 1/72 inci)
opacity10–1
x, yKoordinat manual; menimpa position

Watermark

POST /v1/watermark

Menambahkan teks miring transparan (atau gambar) di seluruh halaman PDF.

<?php
$ch = curl_init('https://docs.suryacloud.my.id/v1/watermark');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . SURYADOCS_API_KEY],
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => [
        'file'    => new CURLFile('/path/dokumen.pdf'),
        'text'    => 'RAHASIA',
        'opacity' => '0.15',
        'pages'   => 'all',
    ],
]);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);
FieldDefaultKeterangan
textTeks watermark (wajib, kecuali memakai asset)
assetGambar watermark, alternatif dari text
opacity0.150–1
rotation45Derajat
pagesallSama seperti overlay

Tanda tangan

POST /v1/sign

Menempelkan gambar tanda tangan pada posisi tertentu. Parameternya sama persis dengan overlay, hanya default-nya berbeda: position=bottom-right, pages=last, width=140.

Ini adalah stempel visual, bukan tanda tangan elektronik tersertifikasi. Endpoint ini menempelkan gambar ke atas halaman PDF. Ia tidak membuat tanda tangan kriptografis (PAdES) dan tidak memiliki kekuatan hukum sebagai tanda tangan elektronik tersertifikasi. Untuk itu diperlukan penyelenggara sertifikasi elektronik (PSrE) terdaftar Kominfo — di luar cakupan layanan ini untuk saat ini.

Template — HTML ke PDF

POST /v1/templates/{id}/render

Simpan template HTML sekali di dashboard, lalu render berkali-kali dengan data berbeda. Placeholder ditulis {{nama_field}} dan mendukung jalur bertitik seperti {{invoice.total}}.

<?php
// Simpan template HTML sekali lewat dashboard, lalu render berkali-kali
// dengan data berbeda. Placeholder ditulis {{nama_field}}.
$ch = curl_init('https://docs.suryacloud.my.id/v1/templates/' . $templateId . '/render');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . SURYADOCS_API_KEY,
        'Content-Type: application/json',
    ],
    CURLOPT_POST       => true,
    CURLOPT_POSTFIELDS => json_encode([
        'data' => [
            'nama'    => 'Budi Santoso',
            'nomor'   => '001/SD/VIII/2026',
            'tanggal' => '20 Agustus 2026',
        ],
    ]),
]);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);

Setiap nilai yang disisipkan otomatis di-escape sebagai HTML, sehingga data dari pengguna akhir Anda tidak dapat menyuntikkan markup ke dalam dokumen. Gambar berformat URL di dalam template kami unduh dan sematkan sendiri sebelum dirender.

Webhook

Daftarkan URL penerima di dashboard, dan kami akan mengirim POST berisi JSON setiap kali pekerjaan selesai — tidak perlu polling.

Setiap pengiriman menyertakan header tanda tangan:

X-Webhook-Signature: sha256=<hmac-sha256 dari body mentah>
Selalu verifikasi tanda tangan. Tanpa verifikasi, siapa pun yang tahu URL penerima Anda bisa mengirim data palsu. Hitung HMAC terhadap body mentah — bukan hasil json_decode yang di-encode ulang, karena urutan kunci dan spasi bisa berubah dan tanda tangan tidak akan cocok. Ini kesalahan integrasi paling umum.

PHP

<?php
// terima-webhook.php — daftarkan URL ini di dashboard SuryaDocs.
// PENTING: verifikasi tanda tangan terhadap BODY MENTAH, bukan hasil
// json_decode lalu di-encode ulang (urutan kunci bisa berubah).
$raw       = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected  = 'sha256=' . hash_hmac('sha256', $raw, SURYADOCS_WEBHOOK_SECRET);

// hash_equals: perbandingan waktu-konstan, bukan ===
if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('signature tidak valid');
}

$event = json_decode($raw, true);
if ($event['event'] === 'job.succeeded') {
    $jobId     = $event['job']['id'];
    $resultUrl = $event['job']['resultUrl'];
    // ... unduh dan simpan hasilnya
}
http_response_code(200);
echo 'ok';

Node.js

import crypto from 'node:crypto';

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.header('x-webhook-signature') ?? '';
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.SURYADOCS_WEBHOOK_SECRET)
    .update(req.body)              // Buffer mentah, bukan objek hasil parse
    .digest('hex');

  const ok = signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  if (!ok) return res.status(401).send('signature tidak valid');

  const event = JSON.parse(req.body.toString());
  res.sendStatus(200);
});

Python

import hmac, hashlib

@app.post("/webhook")
def webhook():
    raw = request.get_data()                 # bytes mentah
    signature = request.headers.get("X-Webhook-Signature", "")
    expected = "sha256=" + hmac.new(
        SURYADOCS_WEBHOOK_SECRET.encode(), raw, hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected, signature):
        return "signature tidak valid", 401

    event = request.get_json()
    return "ok", 200

Pengiriman yang gagal karena masalah sementara diulang hingga 3 kali (jeda 2 dan 5 detik). Balasan 4xx dianggap permanen dan tidak diulang. Setelah 10 kegagalan berturut-turut, endpoint dinonaktifkan otomatis dan bisa diaktifkan lagi dari dashboard.

Widget embed

Untuk kebutuhan di sisi browser — misalnya membiarkan pengunjung situs Anda mengunggah dan mengonversi dokumen sendiri — tempelkan cuplikan ini. Tidak perlu backend, dan API key rahasia Anda tidak pernah ikut terkirim.

<!-- Tempel di halaman web Anda. Tidak perlu backend sama sekali. -->
<div id="suryadocs-widget"
     data-pk="pk_live_xxxxxxxxxxxx"
     data-mode="convert"
     data-height="420px"></div>
<script src="https://docs.suryacloud.my.id/widget/v1/suryadocs.js" async></script>
AtributKeterangan
data-pkKunci publik (pk_live_…) dari dashboard
data-modeconvert atau watermark
data-heightTinggi widget, contoh 420px
Kunci publik memang terlihat di kode halaman Anda — itu wajar, sama seperti kunci publik penyedia pembayaran. Ia hanya bisa membuat pekerjaan atas nama akun Anda dan membaca hasil pekerjaannya sendiri; ia tidak bisa mengakses data akun, kunci lain, atau pekerjaan yang Anda kirim lewat API rahasia. Batasi domain yang boleh memakainya di dashboard, dan pantau pemakaiannya di sana.

Kode error

KodeArti
400Permintaan tidak valid — berkas salah format, parameter keliru
401API key tidak ada, salah, atau sudah dicabut
402Saldo tidak mencukupi — isi saldo di dashboard
403Akun ditangguhkan
404Pekerjaan atau template tidak ditemukan
409Hasil diminta sebelum pekerjaan selesai
410Berkas hasil sudah kedaluwarsa dan dihapus
413Berkas melebihi 20 MB
429Terlalu banyak permintaan — lihat header Retry-After

Setiap respons error menyertakan requestId. Sertakan nilai itu bila menghubungi dukungan — dengan itu kami bisa menemukan permintaan Anda persis di log.

Batas & retensi

HalNilai
Ukuran berkas maksimal (API)20 MB
Permintaan per menit30 per API key
Pekerjaan bersamaan5 per akun
Retensi berkas hasil24 jam

Berkas yang Anda unggah dihapus segera setelah pekerjaan selesai. Berkas hasil dihapus otomatis setelah 24 jam — unduh dan simpan di sistem Anda sendiri. Setelah itu resultUrl akan menjawab 410.