REST API dan Endpoint Publik
Dokumen ini merangkum dua surface backend yang aktif di Biver.
Gunakan API worker untuk integrasi eksternal berbasis API key, lalu gunakan Next.js app routes untuk interaksi publik yang berjalan langsung dari landing page atau dashboard.
Biver Builders Hub
Pemilik akun dapat membuka dashboard Biver untuk melihat informasi komunitas dan pembaruan produk.
Pilih surface yang tepat
| Surface | Base URL | Kapan dipakai |
|---|
| Cloudflare API Worker | https://api.biver.id | Integrasi developer, automation, dan akses workspace berbasis API key. |
| Next.js App Routes | https://biver.id | Dashboard, published landing page, form submit publik, checkout submit, UV code, dan analytics beacon. |
- Endpoint worker mengikuti envelope standar:
success, data, dan meta untuk paginasi.
- Endpoint app tidak memakai satu envelope global. Beberapa route mengembalikan
success, beberapa hanya error, dan POST /api/analytics/track selalu merespons 204.
- Status
Partial berarti route aktif tetapi masih punya batas implementasi. Status Placeholder berarti route aktif namun hasilnya masih dummy atau belum menyimpan data final.
Contoh cepat
List pages via API worker
curl -X GET 'https://api.biver.id/v1/pages?page=1&limit=20' \
-H 'X-API-Key: bvr_live_xxxxx'
Submit form dari landing page
curl -X POST 'https://biver.id/api/forms/FORM_ID/submit' \
-H 'Content-Type: application/json' \
-d '{
"payload": {
"name": "Budi",
"email": "budi@example.com",
"message": "Saya ingin demo"
}
}'
Kirim analytics beacon
curl -X POST 'https://biver.id/api/analytics/track' \
-H 'Content-Type: application/json' \
-d '{
"pageId": "PAGE_UUID",
"sessionId": "sess_12345678",
"eventType": "page_view"
}'
Cloudflare API Worker
Surface ini dipakai untuk integrasi programmatic berbasis API key dan berada di domain api.biver.id.
Base URL: https://api.biver.id
Dokumentasi dan kesehatan
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /health | Tanpa auth | Implemented | Tanpa body. Dipakai untuk health check worker. | Envelope success standar dengan status, version, dan timestamp. |
| GET | /docs | Tanpa auth | Implemented | Mengembalikan dokumentasi markdown yang sama dengan halaman REST API publik. | Markdown text response. |
| GET | /SKILL.md | Tanpa auth | Implemented | Alias markdown untuk agent atau automation. | Markdown text response. |
| GET | /docs/api.json | Tanpa auth | Implemented | Spec JSON terstruktur yang dihasilkan dari kontrak endpoint bersama. | JSON terstruktur dengan metadata surface dan daftar endpoint. |
Pages
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/pages | API key | Implemented | Query: page, limit, status? (draft|published|archived|trash), fields=summary (tanpa sectionsJson), q (cari judul atau slug), sort (updated|created|title). Tanpa fields bentuk lama tetap. | Envelope success paginasi. Mode summary: id, title, slug, status, subdomain, pathSlug, customDomain, liveUrl, editorUrl, sectionCount, timestamp. status=trash menambah trashedAt_ms dan purgeAfter_ms. |
| GET | /v1/pages/:id | API key | Implemented | Identifier bisa id atau slug workspace. | Envelope success satu page. Selain field lama: contentHash (kirim balik sebagai baseContentHash), subdomain, pathSlug, customDomain, deployedUrl, liveUrl, editorUrl, ogImage, id pixel, themeMode, hasGlobalCss. |
| POST | /v1/pages | API key | Implemented | Body: title, slug, description?, sectionsJson?, metaTitle?, metaDescription?. sectionsJson melewati sanitizer yang sama dengan app. Halaman baru memakai CSS global dan pengaturan bawaan seperti halaman dari builder. | Envelope success dengan data page baru. Slug sudah dipakai: 409 SLUG_TAKEN. |
| PATCH | /v1/pages/:id | API key | Implemented | Body partial. baseContentHash opsional (409 PAGE_CONFLICT dengan details.currentContentHash bila beda). status hanya archived: published dan draft ditolak 400 INVALID_STATUS, pakai /deploy dan /unpublish. | Envelope success dengan data page terbaru. Slug dipakai halaman lain: 409 SLUG_TAKEN. |
| POST | /v1/pages/:id/deploy | API key | Implemented | Body opsional: subdomain?, pathSlug?. Identifier boleh id atau slug. | Envelope success dengan page, deployResult, dan publishStatus (canonical/public URL + validation snapshot). Penolakan kebijakan konten: 422 POLICY_BLOCKED dengan details policyReview, blockedPhrase, suggestions. |
| GET | /v1/pages/:id/publish-status | API key | Implemented | Snapshot status publish: canonical/public URL, validation terakhir, latest success attempt, latest failed attempt. | Envelope success satu objek publish status. |
| GET | /v1/pages/:id/deployments?limit={n} | API key | Implemented | Riwayat deployment attempt terbaru, default limit 20. | Envelope success array deployment attempt dengan ringkasan validation/error. |
| DELETE | /v1/pages/:id | API key | Implemented | Menghapus page workspace. | Envelope success dengan message. |
| GET | /v1/pages/:id/versions | API key | Implemented | Query: limit (1-50), cursor?, source? (autosave|manual|ai|publish|restore|api). | data: versions[], nextCursor, limits (maxVersions, retentionDays, used, pinned, maxPinned). |
| GET | /v1/pages/:id/versions/:versionId?include=content&compare=current | API key | Implemented | Query opsional: include=content (isi tersimpan), compare=current (ringkasan beda terhadap draft). | data: version, sections?, content?, contentOmitted? (too_large), diff? (apa yang terjadi bila versi dipulihkan: added = section yang kembali, removed = section yang hilang dari draft, changed, moved). Error: VERSION_NOT_FOUND (404). |
| POST | /v1/pages/:id/versions | API key | Implemented | Body opsional: label (maks 120 karakter). Menyimpan draft sebagai versi manual. | data: version, created. 201 bila baru, 200 dengan reason unchanged bila isi sama dengan versi terakhir. 402 bila batas versi paket penuh. |
| PATCH | /v1/pages/:id/versions/:versionId | API key | Implemented | Body: label? (null menghapus), isPinned?. Minimal satu field. | data: version. 402 bila batas sematan (10) penuh. |
| DELETE | /v1/pages/:id/versions/:versionId | API key | Implemented | Menghapus satu versi. Tidak bisa dipulihkan. | data: deleted, versionId. |
| POST | /v1/pages/:id/versions/:versionId/restore | API key | Implemented | Body opsional: baseContentHash. Draft dikembalikan ke versi itu. Draft sebelumnya disimpan sebagai versi restore. | data: pageId, title, sectionCount, restoredFrom, safetyVersion, contentHash, needsRepublish. 409 PAGE_CONFLICT bila hash tidak cocok. |
| POST | /v1/pages/:id/restore | API key | Implemented | Tanpa body. Mengeluarkan halaman dari Sampah sebagai draft. | data: pageId, status, restoredAddress, editorUrl. 402 dengan details entitlement bila batas halaman penuh. 409 NOT_IN_TRASH. |
| POST | /v1/pages/:id/sections/ai | API key | Implemented | Scope pages:write dan ai:generate. Body: brief (10-2000), type? (default content), position? atau afterSectionId?, baseContentHash?. Header Idempotency-Key opsional (10 menit). | data: section, position, sectionCount, contentHash, needsRepublish (201). Memakai 1 aksi AI mingguan. 402 entitlement, 409 PAGE_CONFLICT, 502 AI_OUTPUT_UNUSABLE (kuota dikembalikan). |
Sections
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/sections/types | API key | Implemented | List section type valid + schema hint ringkas. | Envelope success berisi daftar type, requiredFields, optionalFields. |
| GET | /v1/sections/types/:type | API key | Implemented | Detail schema hint per section type. | Envelope success satu type dengan examplePayload. |
| GET | /v1/sections?pageId={pageId} | API key | Implemented | Query: pageId wajib, sectionIds (maks 50, pisah koma), fields (html, css, js, data, advanced, seo, preview; id, type, name, visible, order selalu ikut). | Envelope success dengan array section. meta.missingSectionIds bila ada id yang tidak ada. Halaman tidak ada, di Sampah, atau milik workspace lain: 404 PAGE_NOT_FOUND. |
| POST | /v1/sections?pageId={pageId} | API key | Implemented | Body section baru, baseContentHash opsional. pageId tetap lewat query, bukan body. POST /bulk, PATCH /:id, dan POST /reorder juga menerima baseContentHash. | Envelope success dengan daftar section terbaru. 409 PAGE_CONFLICT dengan details.currentContentHash bila hash beda. Halaman tidak ada, di Sampah, atau milik workspace lain: 404 PAGE_NOT_FOUND. |
| POST | /v1/sections/bulk?pageId={pageId} | API key | Implemented | Body: mode (atomic|best_effort, default atomic), sections[]. | Envelope success berisi appliedCount, errorCount, errors, dan sections terbaru. |
| PATCH | /v1/sections/:id?pageId={pageId} | API key | Implemented | Body partial section. pageId tetap query wajib. | Envelope success satu section. Error validasi menyertakan missingFields/invalidFields/examplePayload. |
| DELETE | /v1/sections/:id?pageId={pageId} | API key | Implemented | Hapus section dari page tertentu. | Envelope success dengan message. |
| POST | /v1/sections/reorder?pageId={pageId} | API key | Implemented | Body: sectionIds[]. | Envelope success dengan urutan section terbaru. |
| POST | /v1/sections/import-html | API key | Implemented | Body: pageId, html (maks 200.000 karakter), position?, baseContentHash?. | data: sections[], position, sectionCount, contentHash, globalCssAdded, ignored (globalJs, externalScripts, externalStylesheets), warnings, needsRepublish. JS global dan script eksternal tidak diterapkan. |
| POST | /v1/sections/:id/ai-edit?pageId={pageId} | API key | Implemented | Scope sections:write dan ai:generate. Body: instruction (5-2000), selector?, baseContentHash?. Header Idempotency-Key opsional. | data: section, contentHash, needsRepublish. Memakai 1 aksi AI mingguan. Error: SECTION_NOT_FOUND, PAGE_CONFLICT, AI_OUTPUT_UNUSABLE. |
Products
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/products | API key | Implemented | Query: page, limit, isActive? (true atau false). | Envelope success paginasi produk. |
| GET | /v1/products/:id | API key | Implemented | Identifier bisa id atau slug workspace. | Envelope success satu produk. |
| POST | /v1/products | API key | Implemented | Body produk baru: name, slug?, price (integer Rupiah), comparePrice?, description?, image?, isActive?, metadata?, requiresShipping?, weightGram?. description, comparePrice, dan image boleh null. | Envelope success produk baru. |
| PATCH | /v1/products/:id | API key | Implemented | Body partial produk. price dan comparePrice harus integer. null pada description, comparePrice, atau image mengosongkan field. Field yang tidak dikirim tetap. | Envelope success produk terbaru. |
| DELETE | /v1/products/:id | API key | Implemented | Menghapus produk workspace. | Envelope success dengan message. |
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/forms | API key | Implemented | Query: page, limit, isActive?. | Envelope success paginasi form definition, termasuk fields/settings ter-parse dan fieldCount. |
| GET | /v1/forms/:id | API key | Implemented | Identifier bisa id atau slug form dalam workspace. | Envelope success satu form definition dengan fields/settings ter-parse. |
| POST | /v1/forms | API key | Implemented | Body: name, slug?, fields[], settings?, isActive?. Slug kosong akan dibuat unik otomatis. | Envelope success form baru. |
| PATCH | /v1/forms/:id | API key | Implemented | Body partial: name?, slug?, fields?, settings?, isActive?. Identifier bisa id atau slug. | Envelope success form yang sudah diperbarui. |
| GET | /v1/forms/submissions | API key | Implemented | Query: page, limit, formId?. | Envelope success paginasi submission form. |
| POST | /v1/forms/submit | API key | Implemented | Body: formDefinitionId, pageId?, sectionId?, payload, meta?. | Envelope success submission baru dengan validasi schema form. Route ini bukan public form endpoint dashboard. |
| POST | /v1/forms/:id/submit | API key | Implemented | Body: pageId?, sectionId?, payload, meta?. Identifier bisa id atau slug. | Envelope success submission baru by form identifier. |
Gallery
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/gallery | API key | Implemented | Query: page, limit, prefix?. | Envelope success paginasi gallery item. |
| GET | /v1/gallery/:id | API key | Implemented | Detail gallery item terikat workspace. | Envelope success satu item. |
| POST | /v1/gallery | API key | Implemented | Upload multipart form-data file (maks 5 MB, tipe diambil dari isi file: JPEG, PNG, WebP, GIF) atau JSON base64. | Envelope success item baru. Alias /upload juga tersedia. |
| POST | /v1/gallery/upload | API key | Implemented | Alias upload multipart form-data. | Envelope success item baru. Perilakunya sama dengan POST /v1/gallery. |
| DELETE | /v1/gallery/:id | API key | Implemented | Menghapus gallery item beserta object bucket terkait. | Envelope success dengan message. |
| POST | /v1/gallery/import-url | API key | Implemented | Body: url (https saja), name?, altText?, folder?. Host privat, localhost, IPv6, port khusus, dan redirect ke host privat ditolak. Maks 5 MB, tipe dari isi file. | Item gallery dengan url dan thumbnailUrl (201). Error: INVALID_IMAGE_URL, IMAGE_TOO_LARGE, INVALID_IMAGE, IMAGE_FETCH_FAILED, 402 kuota storage. |
AI helper routes
| Method | Path | Auth | Status | Request | Response |
|---|
| POST | /v1/ai/fields/generate | API key | Implemented | Scope ai:generate. Body: pageId, field (seo_title | seo_description | text), context? (wajib untuk text). Header Idempotency-Key opsional. | data: field, text, characters. Tidak menyimpan apa pun. Memakai 1 aksi AI mingguan. |
| GET | /v1/ai/context | API key | Implemented | Ringkasan workspace, pages, products, dan forms untuk konsumsi AI. | Envelope success context AI, termasuk fieldCount, fields[] ter-parse, dan penanda hidden/query-param form. |
| GET | /v1/ai/context/pages/:id | API key | Implemented | Context detail satu page, termasuk sectionsJson yang sudah diurai. | Envelope success page context. |
| GET | /v1/ai/pages | API key | Implemented | List pages dalam format yang lebih ramah AI. | Envelope success paginasi hasil transformasi data page. |
| GET | /v1/ai/pages/:id | API key | Implemented | Detail page plus sections dengan htmlContent dan cssContent. | Envelope success page format AI. |
| POST | /v1/ai/pages | API key | Implemented | Body generate page: prompt, title?, slug?, type?, industry?, tone?, sections?. | Diproses oleh action AI internal kanonik dengan kuota workspace yang sama seperti dashboard. |
| POST | /v1/ai/pages/generate | API key | Implemented | Alias generate page dengan body yang sama. | Alias action AI internal yang sama dengan POST /v1/ai/pages. |
| GET | /v1/ai/sections?pageId={pageId} | API key | Implemented | List sections dalam format AI. | Envelope success sections. |
| POST | /v1/ai/sections | API key | Implemented | Body generate section: pageId, type, prompt, position?, context?. | Diproses oleh action AI internal kanonik dengan kuota workspace yang sama seperti dashboard. |
| POST | /v1/ai/sections/generate | API key | Implemented | Alias generate section dengan body yang sama. | Alias action AI internal yang sama dengan POST /v1/ai/sections. |
| GET | /v1/ai/sections/templates | API key | Implemented | List template type section untuk helper AI. | Envelope success daftar template statis. |
| GET | /v1/ai/images/models | API key | Implemented | Mengambil satu capability image tetap serta snapshot kredit workspace (base mingguan + top-up). | Envelope success dengan model cx/gpt-5.5-image, baseCredit, pricing top-up, dan kredit tersisa. |
| POST | /v1/ai/images/generate | API key | Implemented | Body ketat: prompt. Header Idempotency-Key opsional. Workspace otomatis dari API key. | Envelope success async task dengan jobId, status, pricing, dan credit; tidak mengekspos task ID upstream. |
| GET | /v1/ai/images/tasks/:jobId | API key | Implemented | Polling status task image berdasarkan jobId. | Envelope success dengan jobId, status, galleryImageId saat selesai, storage, dan credit. |
Domains
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/domains | API key | Implemented | Query: page, limit, status?. | Envelope success paginasi domain workspace. |
| GET | /v1/domains/:id | API key | Implemented | Detail domain dan status verifikasi. | Envelope success satu domain. |
| POST | /v1/domains | API key | Implemented | Body: domain, isPrimary?, landingPageId?. | Envelope success domain baru. |
| PATCH | /v1/domains/:id | API key | Implemented | Body partial: isPrimary?, landingPageId?. | Envelope success domain terbaru. |
| DELETE | /v1/domains/:id | API key | Implemented | Menghapus domain workspace. Hostname Cloudflare dihapus, salinan halaman di domain itu dibersihkan, tautan ke halaman dilepas. | data: id, domain, deleted, newPrimaryDomainId (domain lain dari halaman yang sama bila ini primary), warnings. 502 DOMAIN_REMOVE_FAILED bila penyedia gagal: baris tetap ada, ulangi. |
| POST | /v1/domains/:id/primary | API key | Implemented | Menandai domain sebagai primary domain dari halaman yang memakainya. Domain harus terverifikasi dan terhubung ke halaman. PATCH isPrimary=true memakai aturan yang sama. | Envelope success domain terbaru. 409 DOMAIN_NOT_VERIFIED atau DOMAIN_NOT_ASSIGNED bila syarat belum terpenuhi. |
Subdomains
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/subdomains | API key | Implemented | Query: page, limit, status?. | Envelope success paginasi page yang memiliki subdomain. |
| GET | /v1/subdomains/:id | API key | Implemented | Detail landing page yang diekspos sebagai subdomain. | Envelope success satu subdomain. |
| POST | /v1/subdomains | API key | Implemented | Body: subdomain, title, description?, pathSlug?. Subdomain adalah halaman baru, jadi batas halaman paket berlaku. | Envelope success subdomain baru. 402 dengan details entitlement bila batas halaman penuh. |
| PATCH | /v1/subdomains/:id | API key | Implemented | Body partial: subdomain?, title?, description?, pathSlug?, status?, SEO fields. subdomain baru lewat alur PUT /v1/pages/:id/subdomain: file terbit dipindah ke alamat baru. Judul berubah tidak mengubah slug. | Envelope success subdomain terbaru. |
| DELETE | /v1/subdomains/:id | API key | Implemented | Menghapus subdomain workspace. | Envelope success dengan message. |
Workspace
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/workspace/settings | API key | Implemented | Mengambil settings workspace dari worker. | Envelope success settings workspace. |
| PATCH | /v1/workspace/settings | API key | Implemented | Body general settings: description, socialLinks, analytics, customCss, customJs, contact info, timezone, currency, language. | Envelope success settings terbaru. |
| PATCH | /v1/workspace/branding | API key | Implemented | Body branding: title, logo, favicon, logoDark, primaryColor, secondaryColor. | Envelope success branding terbaru. |
| PATCH | /v1/workspace/seo | API key | Implemented | Body SEO defaults: defaultMetaTitle, defaultMetaDescription, defaultOgImage, defaultTwitterCard, keywords. | Envelope success SEO defaults terbaru. |
| GET | /v1/workspace/public | API key | Implemented | Mengambil public info workspace aktif. | Envelope success info publik workspace. |
| PATCH | /v1/workspace | API key | Implemented | Scope workspace:write. Body: name (1-100). Hanya owner dan admin. | data = settings workspace terbaru. Slug tidak bisa diubah: body dengan slug dijawab 403 DASHBOARD_ONLY dan tidak ada yang berubah. Error: ROLE_NOT_ALLOWED (403). |
| GET | /v1/workspace/plans | API key | Implemented | Scope workspace:read. | data = { currentPlan, plans [{ plan, planId, name, price, priceQuarterly, priceSemiannually, priceYearly, popular, isCurrent, move (current, upgrade, downgrade), upgradeUrl, limits { landingPages, aiActionsPerWeek, dailyVisitors, dailyOrders, customDomains, storageBytes, pageVersions, pageVersionRetentionDays, dataRetentionDays, canRemoveBranding, supportLevel } }], billingUrl }. Limit null berarti tanpa batas. Data dari tabel paket. API tidak membayar paket. |
| GET | /v1/workspace/notifications | API key | Implemented | Scope workspace:read. Hanya owner, admin, dan staff. | data = { settings { emailLeadNew, emailOrderNew, emailOrderPaid, buyerEmailEnabled, mutedFormIds, mutedPageIds, buyerContactEmail, buyerContactWhatsapp }, whatsapp { configured, enabled, templateName, templateLanguage, recipientPhoneMasked, lastTestAt_ms, planAllowed, minPlan }, recipients [{ name, role }] }. Token WhatsApp tidak pernah dikembalikan. |
| PATCH | /v1/workspace/notifications | API key | Implemented | Scope workspace:write. Hanya owner dan admin. Body: settings? (field yang sama dengan GET, mutedFormIds dan mutedPageIds harus milik workspace) dan whatsapp? { enabled?, templateName?, templateLanguage? }. Saluran WhatsApp harus sudah dipasang di dashboard. | data = { settings, whatsapp }. Error: DASHBOARD_ONLY (403) bila body whatsapp berisi accessToken, token, phoneNumberId, atau recipientPhone, WHATSAPP_NOT_CONFIGURED (409), FEATURE_NOT_IN_PLAN (402) untuk mengaktifkan WhatsApp di paket yang tidak menyertakannya, FORM_NOT_FOUND atau PAGE_NOT_FOUND (404), ROLE_NOT_ALLOWED (403). |
| GET | /v1/workspace/notifications/deliveries?status={status}&eventType={eventType}&channel={channel}&page={page}&limit={limit} | API key | Implemented | Scope workspace:read. Hanya owner dan admin. limit 1-50 (default 20). | Envelope paginated, terbaru dulu. Setiap row: id, eventType, channel, subjectType, subjectId, recipientKind, recipientMasked, status (queued, sent, failed, dead, suppressed), attempts, errorCode, createdAt_ms, sentAt_ms. Alamat selalu disamarkan. |
| GET | /v1/workspace/onboarding | API key | Implemented | Scope workspace:read. | data = { available, onboarding }. onboarding: stage, survey, checklist { path, dismissed, done, total, items [{ key, title, status, url }], advanced }, nextAction { key, title, cta, url }. available false dan onboarding null berarti checklist belum aktif untuk workspace ini. Itu bukan error. |
| GET | /v1/workspace/announcements | API key | Implemented | Scope workspace:read. | data = pengumuman platform yang sedang aktif, terbaru dulu, paling banyak 10: id, title, message, type, startsAt_ms, endsAt_ms, createdAt_ms. |
Tracking worker API
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/tracking/elements?pageId={pageId} | API key | Implemented | Memindai section button yang memiliki trackingId di sectionsJson. | Envelope success dengan daftar trackable elements. |
| POST | /v1/tracking/events | API key | Partial | Body event tracking dengan pageId, workspaceId, eventId, eventType, trackingId, dan metadata lain. | Envelope success sederhana. Event masih dicatat ke log, belum ke storage permanen. |
| GET | /v1/tracking/events?pageId={pageId} | API key | Placeholder | Query: pageId wajib, limit?, offset?. | Saat ini mengembalikan array kosong dan pesan bahwa event storage belum diimplementasikan. |
| GET | /v1/tracking/visitor-codes/:code | API key | Implemented | Scope tracking:read. Kode tidak membedakan huruf besar dan kecil. | data = { code, page { id, title, slug } atau null, tracking { gclid, fbclid, ttclid, li_fat_id, msclkid, wbraid, gbraid, utmSource, utmMedium, utmCampaign, utmContent, utmTerm }, createdAt_ms, expiresAt_ms, firstUsedAt_ms, lastUsedAt_ms, usageCount }. IP, user agent, dan session id tidak dikembalikan. Error: VISITOR_CODE_NOT_FOUND (404, juga untuk kode workspace lain). |
Wallet (Saldo Biver)
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/wallet | API key | Implemented | Tanpa body. Returns wallet summary untuk workspace milik API key. | Envelope success dengan totalIncome, totalNetIncome, totalWithdrawn, availableBalance (hanya kredit yang sudah settle), pendingBalance (kredit yang menunggu settle), currency IDR. Workspace tanpa wallet returns nilai 0. |
| GET | /v1/wallet/transactions?type={type}&from={from}&to={to}&page={page}&limit={limit} | API key | Implemented | Scope wallet:read. Query: type (credit, debit, credit_reversal), from dan to (tanggal Asia/Jakarta atau epoch ms, batas ikut dihitung), page, limit 1-100. | Envelope paginated, terbaru dulu. Error: VALIDATION_ERROR bila tanggal salah atau from lebih besar dari to. |
| GET | /v1/wallet/transactions/:id | API key | Implemented | Scope wallet:read. | data = mutasi dengan order { id, orderId, paymentMode, paymentStatus } bila ada. Error: TRANSACTION_NOT_FOUND (404, juga untuk mutasi workspace lain). |
Analytics (Omzet dan Traffic)
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/analytics/revenue?period=today|week|month | API key | Implemented | Query: period (default today). Timezone Asia/Jakarta. Menghitung order lunas: paid, processing, completed, cod_collected, serta shipped dan delivered bila bukan COD. | Envelope success: period, startedAt_ms, endedAt_ms, currency IDR, paidOrderCount, totalRevenue, averageOrderValue. |
| GET | /v1/analytics/traffic?period=today|week|month | API key | Implemented | Query: period (default today). week dan month berarti 7 dan 30 hari terakhir, sama dengan dashboard member. Pengunjung dan view dibaca dari pencatat halaman. totalEvents dan eventBreakdown dibaca dari event konversi. | Envelope success: period, totalVisitors (sesi unik), views, uniqueSessions, ctaClicks, formSubmits, topPages, trafficSources, dataAvailable, windowDays, caveats, totalEvents, eventBreakdown[{canonicalEvent, count}] sampai 20 events. Untuk period today, field pengunjung bernilai null dan dataAvailable false karena pencatat halaman tidak bisa menghitung satu hari. Itu bukan nol. |
| GET | /v1/analytics/summary | API key | Implemented | Scope analytics:read. Tanpa query. Bulan mengikuti Asia/Jakarta. | data = { currency, timezone, asOf_ms, thisMonth, lastMonth { startedAt_ms, endedAt_ms, orders, paidOrders, revenue }, allTime { orders, paidOrders, revenue, averageOrderValue }, ordersByStatus (semua status, 0 bila kosong), paymentModes [{ paymentMode, orderCount, paidOrderCount, revenue }], formOrders { total, byStatus }, products { total, active } }. Omzet memakai aturan order lunas yang sama dengan /v1/analytics/revenue. |
Checkout (Riwayat Order)
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/checkout/orders?page={page}&limit={limit}&status={status}&paymentMode={paymentMode}&q={q}&from={from}&to={to} | API key | Implemented | Paginated list CheckoutOrder. status filter opsional: pending_payment, paid, processing, completed, failed, expired, cancelled, pending_cod, confirmed, shipped, delivered, cod_collected, returned. paymentMode filter opsional: manual, biver_gateway, user_gateway, cod, doit_gateway. q mencari nomor order, nama pembeli, dan telepon (format 0812, +62 812, atau 62812 sama saja). from dan to: tanggal Asia/Jakarta atau epoch ms, batas ikut dihitung. | Envelope paginated. Setiap row: id, orderId, pageId, customerName, customerEmail, customerPhone, totalAmount, subtotalAmount, discountAmount, shippingAmount, codFeeAmount, couponCode, shippingMode, shippingCourier, shippingService, currency, paymentMode, paymentStatus, dokuPaymentUrl, createdAt_ms, updatedAt_ms. |
| GET | /v1/checkout/orders/:idOrOrderId | API key | Implemented | Lookup single order by primary id (UUID) atau orderId (BVR-style). | Envelope success dengan single order object atau 404 NOT_FOUND. Detail menambah items[{productId, name, price, quantity, subtotal, image, kind}] (kind: product atau bump), customerData, notes, shippingAddress, manualConfirmedAt_ms, shippingTrackingNumber, warnings, events[{id, fromStatus, toStatus, actorType, note, createdAt_ms}] (terlama dulu), dan phoneStats { codOrders, returned } untuk order COD (null untuk mode lain). |
| PATCH | /v1/checkout/orders/:idOrOrderId | API key | Implemented | Scope checkout:write. Body: status?, note? (maks 1000 karakter), trackingNumber? (maks 64), courier? (maks 32). Kirim minimal satu field. status boleh kosong: catatan atau nomor resi bisa disimpan tanpa mengubah status. status yang diterima: processing, shipped, delivered, completed, cancelled, confirmed, cod_collected, returned. paid tidak diterima (pakai POST .../confirm). | Envelope success dengan order terbaru dan events (timeline, terlama dulu). note disimpan sebagai event timeline (bersama perubahan status bila ada, atau sebagai event dengan status awal dan akhir yang sama). trackingNumber dan courier disimpan pada order di status apa pun. Error: VALIDATION_ERROR (400, body kosong atau melewati batas), ORDER_STATUS_NOT_ALLOWED (400), NOT_FOUND (404, juga untuk order workspace lain), INVALID_TRANSITION atau STALE_STATUS (409, transisi tidak diizinkan untuk paymentMode atau status sudah berubah). Pesanan COD memakai alur pending_cod, confirmed, shipped, delivered, cod_collected atau returned. |
| POST | /v1/checkout/quote | API key | Implemented | Scope checkout:read cukup. Body: items [{ productId, quantity }], customer? { phone }, shipping? { destinationId, courier, service }, paymentMode?, couponCode?, bump? { bumpId, accepted }. Body tidak boleh berisi harga, total, atau workspaceId. | data = hitungan server: currency, items, shipping, coupon, cod, bump, totals { subtotalAmount, discountAmount, shippingAmount, codFeeAmount, totalAmount }, totalTooLow. Tidak menulis data dan tidak memakai kuota kupon. |
| POST | /v1/checkout/orders | API key | Implemented | Scope checkout:write. Body: paymentMode (manual atau cod), customer { name, phone, email? (wajib untuk manual), customFields? }, items [{ productId, quantity }], shipping? { destinationId, courier?, service?, address { street, landmark? } }, couponCode?, bump?, pageId?, notes?, clientRequestId? (UUID). Header Idempotency-Key (UUID) dipakai bila clientRequestId kosong. Body tidak boleh berisi harga atau total. | Status 201. data = { order { id, orderId, paymentMode, paymentStatus, currency, subtotalAmount, discountAmount, shippingAmount, codFeeAmount, totalAmount, couponCode, createdAt_ms }, replayed }. Permintaan yang sama dengan clientRequestId yang sama mengembalikan order pertama, replayed true, status 200. Tim dan pembeli menerima email seperti order biasa. Error: COD_NOT_AVAILABLE, PAYMENT_MODE_UNAVAILABLE, COUPON_UNAVAILABLE, SHIPPING_UNAVAILABLE, ORDER_LIMIT_REACHED (402), VALIDATION_ERROR. |
| PUT | /v1/checkout/config | API key | Implemented | Scope checkout:write. Body: manualTransferEnabled?, biverGatewayEnabled?, userGatewayEnabled?, codEnabled?, dokuEnvironment?, checkoutPrimaryColor?, checkoutLogo?, checkoutCustomFields?. Field yang dibaca pembeli ditolak: rekening transfer manual (manualBankName, manualAccountNumber, manualAccountHolder, manualInstructions), sellerWhatsapp, dan checkoutThankYouMessage. | Error: DASHBOARD_ONLY (403, details.rejectedFields dan details.dashboardUrl) untuk field rekening, sellerWhatsapp, dan checkoutThankYouMessage, DOKU_CREDENTIALS_NOT_ACCEPTED (400) untuk kunci DOKU. Rekening, nomor WhatsApp penjual, dan pesan terima kasih hanya diisi pemilik di dashboard. |
Checkout (Kupon)
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/checkout/coupons?page={page}&limit={limit} | API key | Implemented | Scope checkout:read. Query: page, limit 1-50 (default 20). | Envelope paginated. Setiap row: id, code, type (percent atau fixed), value, maxDiscountAmount, minSubtotal, maxUses, usedCount, perBuyerLimit, startsAt_ms, expiresAt_ms, productIds, isActive. Hanya owner, admin, dan staff yang membaca kupon. |
| POST | /v1/checkout/coupons | API key | Implemented | Scope checkout:write. Body: code (3-32 karakter A-Z 0-9 _ -, diubah ke huruf besar), type, value (integer, persen 1-100), maxDiscountAmount?, minSubtotal?, maxUses?, perBuyerLimit?, startsAt atau startsAt_ms?, expiresAt atau expiresAt_ms?, productIds? (UUID), isActive?. startsAt dan expiresAt boleh berupa tanggal (2026-10-17, Asia/Jakarta, expiresAt berarti akhir hari) atau waktu ISO. | Status 201. data = kupon baru. Error: COUPON_CODE_TAKEN (409), VALIDATION_ERROR (400), ROLE_NOT_ALLOWED (403). |
| PATCH | /v1/checkout/coupons/:id | API key | Implemented | Scope checkout:write. Body: sebagian field kupon. Hasil gabungan divalidasi ulang. Workspace tidak bisa diganti. | data = kupon terbaru. Error: COUPON_NOT_FOUND (404, juga untuk kupon workspace lain), COUPON_CODE_TAKEN (409), VALIDATION_ERROR (400). |
| DELETE | /v1/checkout/coupons/:id | API key | Implemented | Scope checkout:write. Kupon yang belum pernah dipakai dihapus. Kupon yang sudah dipakai hanya dinonaktifkan. | data = { coupon, deleted }. deleted false berarti kupon hanya dinonaktifkan. Error: COUPON_NOT_FOUND (404). |
Checkout (Order Bump)
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/checkout/bump | API key | Implemented | Scope checkout:read. | data = bump (id, bumpProductId, triggerProductIds, headline, description, bumpPrice, isActive) atau null bila belum ada. |
| PUT | /v1/checkout/bump | API key | Implemented | Scope checkout:write. Body: bumpProductId (UUID produk aktif workspace), headline (1-80), description?, triggerProductIds?, bumpPrice? (integer, null berarti harga produk), isActive?. Satu workspace punya satu bump. Untuk mematikan, kirim isActive false. | data = bump tersimpan. Error: BUMP_PRODUCT_UNAVAILABLE (422), VALIDATION_ERROR (400). |
Checkout (Pengiriman dan COD)
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /v1/checkout/fulfillment | API key | Implemented | Scope checkout:read. | data = { fulfillment, isDefault }. fulfillment: shippingMode (none, free, flat, calculated), originDestinationId, originLabel, couriers, flatRateAmount, freeShippingMinSubtotal, fallbackShippingAmount, sellerWhatsapp, codMaxAmount, codFeeFlatAmount, codAllowedProvinces, codMaxPendingPerPhone, codMaxPerPhonePerDay, codBlockAfterReturns. isDefault true bila belum pernah disimpan. |
| PUT | /v1/checkout/fulfillment | API key | Implemented | Scope checkout:write. Body: satu atau lebih field fulfillment. Field yang tidak dikirim tetap bernilai lama. Hasil gabungan harus valid (mode calculated butuh asal dan kurir, mode flat butuh flatRateAmount). Field sellerWhatsapp ditolak. | data = { fulfillment }. Error: VALIDATION_ERROR (400) dengan pesan aturan yang dilanggar, DASHBOARD_ONLY (403, details.rejectedFields dan details.dashboardUrl) untuk sellerWhatsapp. Nomor WhatsApp penjual hanya diisi pemilik di dashboard. |
Next.js App Routes
Surface ini dipakai oleh dashboard atau published landing page di domain utama Biver.
Base URL: https://biver.id
Image generation app routes
| Method | Path | Auth | Status | Request | Response |
|---|
| GET | /api/images/config?workspaceId={workspaceId} | Session + role workspace | Implemented | Mengambil capability image tetap, preview kredit, pricing top-up, dan penggunaan kredit workspace. | JSON langsung berisi capability cx/gpt-5.5-image, credit (base+topup), creditPricing, dan storage. |
| POST | /api/images/topup/create | Session + role workspace | Implemented | Body: workspaceId, credits. Hanya owner/admin. Membuat/reuse checkout top-up kredit image (DOKU). | JSON langsung: orderId, amount, status, paymentUrl, dan snapshot credit terbaru. |
| GET | /api/images/topup/orders?workspaceId={workspaceId} | Session + role workspace | Implemented | Daftar transaksi top-up image untuk workspace. Hanya owner/admin. | JSON langsung: orders + snapshot credit terbaru. |
| GET | /api/images/topup/orders/:orderId?workspaceId={workspaceId} | Session + role workspace | Implemented | Detail status transaksi top-up image + reconcile status pembayaran bila masih pending. | JSON langsung: detail order + snapshot credit terbaru. |
| POST | /api/images/generate | Session + role workspace | Implemented | Body ketat: workspaceId, prompt, source (dashboard|section). Header Idempotency-Key wajib. | JSON langsung berisi jobId, status pending, pricing, dan snapshot credit. |
| GET | /api/images/tasks/:jobId | Session + role workspace | Implemented | Polling status task image milik workspace. Consumer menyimpan hasil ke folder gallery ai-generated. | JSON langsung berisi jobId, status, galleryImageId saat selesai, storage, serta settle/refund credit. |
Landing page public routes
| Method | Path | Auth | Status | Request | Response |
|---|
| POST | /api/forms/:id/submit | Publik, workspace diambil dari origin | Implemented | Body: workspaceId?, pageId?, sectionId?, payload, meta?. Workspace dan page bisa di-resolve dari referer atau origin. | JSON langsung: success + submissionId. Dipakai form publik dari landing page. |
| POST | /api/checkout/submissions | Publik, workspace diambil dari origin | Implemented | Body: workspaceId?, pageId?, sectionId?, productId?, customer, items, totalAmount, currency?, status?, notes?. | JSON langsung: success + submissionId. Mendukung resolusi workspace dari origin atau product. |
| GET | /api/checkout/submissions | Session + role workspace | Implemented | Query internal dashboard: workspaceId, status?, pageId?. | JSON langsung dengan daftar submissions. |
| POST | /api/public/uv-code | Tanpa auth | Implemented | Body: pageId, sessionId?, trackingParams?. Dipakai published page untuk generate UV code. | JSON langsung: success, code, placeholder. |
| GET | /api/public/uv-code?code={code} | Tanpa auth | Implemented | Lookup tracking data berdasarkan UV code. | JSON langsung dengan tracking params yang terkait code. |
| POST | /api/analytics/track | Tanpa auth | Implemented | Body sendBeacon JSON: pageId, sessionId, eventType, serta metadata device, UTM, CTA, form, atau scroll. | Selalu merespons 204. Event diproses fire-and-forget dengan rate limit per IP. |
MCP Server
Worker yang sama menyediakan MCP server stateless di POST https://mcp.biver.id/mcp. Transport-nya Streamable HTTP dengan JSON-RPC 2.0, tanpa SSE dan tanpa Mcp-Session-Id. Request GET dijawab 405.
| Aspek | Detail |
|---|
| Endpoint | POST https://mcp.biver.id/mcp (OAuth atau API key), POST https://api.biver.id/mcp (API key saja) |
| Auth | OAuth 2.1 dengan PKCE untuk claude.ai, Claude Desktop, dan Claude Code. API key /v1 (Authorization: Bearer bvr_live_xxxxx atau X-API-Key) untuk klien lain. |
| Protocol version | 2025-11-25, juga 2025-06-18 dan 2025-03-26. |
| Method | initialize, ping, tools/list, tools/call, resources/list, resources/templates/list, resources/read, prompts/list, prompts/get. |
| Tool | 48 tool bernama. Tool baca dan tool tulis terpisah. tools/list hanya menampilkan tool yang diizinkan oleh scope koneksi. |
| Scope | Setiap tool memanggil endpoint /v1 di kontrak ini. Scope dan rate limit dicek ulang pada setiap panggilan. |
curl -X POST 'https://api.biver.id/mcp' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer bvr_live_xxxxx' \
-H 'MCP-Protocol-Version: 2025-11-25' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Daftar tool, contoh prompt, dan cara menghubungkan: /docs/claude-connector.
Tutorial lengkap: /docs/mcp-server.
Catatan implementasi penting
PATCH /v1/workspace/settings, PATCH /v1/workspace/branding, dan PATCH /v1/workspace/seo adalah kontrak aktif. Docs lama yang masih menulis PUT sudah tidak berlaku.
POST /v1/forms/submit adalah route worker yang butuh API key. Form publik landing page memakai POST /api/forms/:id/submit di app.
- Worker forms sekarang mengembalikan
fields dan settings ter-parse, tetapi tetap mempertahankan fieldsJson dan settingsJson untuk kompatibilitas.
- Gallery menerima upload di
POST /v1/gallery dan alias POST /v1/gallery/upload.
- Pipeline image memakai satu capability tetap
cx/gpt-5.5-image, Queue Cloudflare, dan pola async submit + polling task. Client tidak memilih provider, model, size, resolution, atau jumlah hasil.
- Seluruh route sections worker yang memodifikasi data (
POST /v1/sections, POST /v1/sections/bulk, PATCH /v1/sections/:id, DELETE /v1/sections/:id, POST /v1/sections/reorder) memakai pageId sebagai query wajib.
- AI page dan section melalui API Worker memanggil action internal yang sama dengan dashboard, memakai model teks tetap dan kuota workspace yang sama.
- Route pengelolaan
/api-keys tidak dipublikasikan oleh API Worker. Buat dan cabut credential hanya dari dashboard Biver.
GET /v1/tracking/events dan penyimpanan event worker belum final. Untuk analytics live landing page, acuan utamanya tetap POST /api/analytics/track.
Copywriting Style Options untuk AI Generation
Chat Biver AI di builder (POST /api/ai/chat, stream SSE) memilih salah satu dari 3 framework copywriting profesional berikut untuk setiap halaman:
Alex Hormozi ($100M Offers)
- Tone: Confident, logical, no fluff, value-driven
- Struktur: Magnetic Headline → Reason Why (Scarcity/Urgency) → Value Equation Breakdown → Offer Stack (main + 3 bonus) → Unbeatable Guarantee → CTA
- Cocok untuk: Direct-response offers, high-ticket products, bisnis jasa dengan value proposition jelas
Russell Brunson (Hook, Story, Offer)
- Tone: Inspirational, high energy, storytelling, empathetic
- Struktur: The Hook (Headline) → The Story (Backstory, The Wall, The Epiphany, The Plan) → The Offer (product list + The Stack) → The Call To Action
- Cocok untuk: Personal brand, coaching, courses, produk berbasis transformasi
Dane Maxwell (The Copywriting Checklist)
- Tone: Clear, customer-focused, benefit-driven
- Struktur: Instant Clarity Headline → Declare Problem → Present Solution → Borrow Credibility → Social Proof → Testimonials → Clear CTA → Reverse Risk → Price Anchoring → FAQ
- Cocok untuk: SaaS, produk teknologi, B2B services, produk yang butuh trust-building
Payload chat builder
Route ini dipakai panel chat di builder dengan sesi login, bukan lewat API key. Satu pesan memakai satu kuota aksi AI.
{
"workspaceId": "WORKSPACE_ID",
"pageId": "PAGE_ID",
"messages": [{"role": "user", "content": "Buat landing page kopi susu gula aren di Bandung"}],
"page": {"title": "", "sections": [], "settings": {"whatsappNumber": "6281234567890"}}
}
Respons berupa event SSE: text_delta, plan, section_start, section_complete, section_error, remove_sections, reorder_sections, page_update, suggestions, lalu done atau error.