Lewati ke konten
Kembali ke dokumentasi Launch

Unduh MarkdownDokumen asli di GitHub

Panduan integrasi sistem lisensi kustom

Kode sumber saat ini mendukung dua penyedia lisensi: Licentivo dan custom_http. Pedagang memilih dan mengaktifkan salah satunya untuk seluruh produk dan lingkungan sandbox/live di Pengaturan sistem → Sistem lisensi; koneksi kustom dan pemetaan paket tetap dikonfigurasi per produk dan lingkungan. Fitur ini tidak mencakup pembangunan sistem lisensi sendiri; pedagang tetap menggunakan layanan lisensi dan SDK miliknya.

Pertukaran akun Licentivo, SDK sembilan bahasa, dan pengelolaan perangkat tetap menggunakan alur yang ada. Produk kustom menyinkronkan status pembelian melalui protokol ini; pelanggan membaca hasil penyampaian lisensi di pusat akun tanpa melalui alur Licentivo SDK.

Mulai cepat

  1. Implementasikan empat endpoint HTTP berikut pada layanan Anda, lalu konfigurasikan kunci penandatanganan HMAC dan pengenal terpisah untuk setiap koneksi.
  2. Di ‘Sistem lisensi’, pilih ‘Layanan lisensi kustom’, tambahkan koneksi, isi alamat, lingkungan, pengenal koneksi, key ID, dan kunci Base64 standar. Setelah diverifikasi, simpan dan klik ‘Aktifkan layanan lisensi kustom’.
  3. Buat draf produk dan paket penjualan. Jenis pembelian dan harga dikelola di Launch; aturan lisensi dikelola di sistem Anda sendiri.
  4. Pilih produk, lingkungan, dan koneksi, lalu isi dan simpan referensi produk serta paket eksternal. Penyedia ditentukan oleh pilihan di seluruh situs; Licentivo tidak dapat diaktifkan bersamaan untuk produk lain.
  5. Terbitkan versi uji di halaman paket penjualan, selesaikan penerimaan pembayaran, penyampaian, perpanjangan, peningkatan, pengembalian dana, dan pemulihan kegagalan, lalu konfigurasikan lingkungan produksi secara terpisah.

Alamat, lingkungan, pengenal koneksi, dan kebijakan akses jaringan tidak dapat diubah setelah dibuat; buat koneksi baru jika diperlukan. Kunci penandatanganan dapat dirotasi; biarkan kosong untuk mempertahankan kunci lama. Jika ada pesanan dari sistem lisensi lain, penyedia seluruh situs tidak dapat langsung diganti; migrasi harus diselesaikan terlebih dahulu. Setelah pergantian, paket lama menjadi hanya pratinjau dan harus diterbitkan ulang; kredensial koneksi dan pemetaan yang tersimpan tetap dipertahankan. Koneksi untuk produk yang sudah memiliki pesanan tidak dapat langsung diganti, begitu pula pemetaan yang sedang dijual; gunakan versi paket baru untuk harga atau pemetaan baru.

Saat mengonfigurasi melalui API, panggil PUT /api/v1/admin/licensing/provider terlebih dahulu dengan isi permintaan {"provider":"custom_http"} atau {"provider":"licentivo"}, lalu simpan pemetaan produk. Penyedia yang tidak diaktifkan tidak dapat menyimpan pengikatan lisensi produk atau pemetaan kebijakan paket Licentivo.

Pemeriksaan koneksi mengonfirmasi protokol, autentikasi, lingkungan, dan jenis pembelian yang didukung; pemeriksaan ini tidak membuat atau mengonfirmasi paket eksternal atas nama pedagang. Sebelum menerima pembayaran produksi, penerimaan integrasi sandbox harus diselesaikan menggunakan paket eksternal yang sebenarnya.

3. Alur integrasi pedagang

  1. Implementasikan empat endpoint dalam dokumen ini di depan sistem lisensi yang ada; logika lisensi yang sudah ada tetap dipertahankan.
  2. Buat koneksi ‘Layanan lisensi kustom’ di Launch, lalu konfigurasikan alamat HTTPS, pengenal koneksi, lingkungan, dan kunci penandatanganan.
  3. Launch memanggil endpoint pemeriksaan kemampuan untuk memastikan versi protokol, dukungan pembelian permanen/berjangka, dan metode penyampaian.
  4. Pilih koneksi tersebut untuk produk; petakan versi paket penjualan ke product_ref dan plan_ref eksternal. Pengenal eksternal dapat berupa string milik pedagang dan tidak harus menggunakan UUID Licentivo.
  5. Selesaikan penerimaan pembayaran, perpanjangan, peningkatan, pengembalian dana, dan pemulihan kegagalan di sandbox, lalu terbitkan konfigurasi live secara terpisah.
  6. Setelah memverifikasi pembayaran, Launch menyimpan pesanan, cakupan pembelian, dan tugas yang menunggu pengiriman dalam transaksi basis data yang sama.
  7. Proses latar belakang mengirimkan snapshot pembelian lengkap ke layanan lisensi kustom; layanan tersebut mengonfirmasi penerimaan setelah menyimpan catatan penerimaan secara persisten.
  8. Layanan lisensi memproses status tujuan. Launch memeriksa tanda terima peristiwa asli dan hanya menganggap sinkronisasi selesai ketika statusnya applied.
  9. Launch membaca informasi penyampaian bagi pelanggan yang sudah masuk dan memiliki pembelian tersebut, lalu menampilkan kode lisensi, akses aktivasi, atau petunjuk teks biasa di pusat pelanggan. Aplikasi terhubung ke sistem lisensi milik pedagang.
  10. Perpanjangan, peningkatan, pengembalian dana, pembalikan pembayaran, penangguhan, dan kedaluwarsa masing-masing menghasilkan snapshot lengkap versi baru. Layanan lisensi memprosesnya berdasarkan status tujuan terbaru.

sandbox/live untuk produk yang sama diikat ke koneksi masing-masing. Setelah ada pembelian, pergantian penyedia memerlukan proses migrasi terpisah; pesanan dan tugas lama tidak boleh diam-diam dikirim ke layanan baru mengikuti pilihan di panel administrasi.

4. API yang harus diimplementasikan oleh layanan lisensi kustom

Semua endpoint berikut diterima oleh layanan lisensi pedagang dan dipanggil oleh server Launch. base_url dapat berisi awalan path tetap; path dalam tabel ditambahkan setelah awalan tersebut.

Metode dan path Tujuan
GET /launch/v1/capabilities Pemeriksaan koneksi serta deklarasi protokol dan kemampuan
POST /launch/v1/events Menerima status tujuan pembelian lengkap; percobaan ulang menggunakan peristiwa asli
GET /launch/v1/events/{event_id} Memeriksa apakah peristiwa benar-benar diterapkan dan memulihkan respons yang hilang
GET /launch/v1/entitlements/{entitlement_ref}/delivery Membaca informasi penyampaian lisensi yang sudah ada tanpa membuat lisensi kedua

Versi pertama menggunakan pemeriksaan tanda terima secara aktif dan tidak menambahkan endpoint callback eksternal untuk mengubah pesanan. Layanan kustom tidak berwenang mengonfirmasi pembayaran, mengubah harga, atau mengubah masa pembelian.

4.1 Ketentuan umum dan autentikasi

  • JSON menggunakan UTF-8; waktu menggunakan UTC RFC 3339; version menggunakan bilangan bulat positif.
  • Respons berhasil adalah {"data": {...}, "request_id": "..."}; respons kesalahan adalah {"error": {"code": "...", "message": "..."}, "request_id": "..."}.
  • Setiap lingkungan dan koneksi menggunakan kunci terpisah. Kunci terdiri atas setidaknya 32 byte acak dan dirujuk dari penyimpanan kunci terenkripsi yang ada di Launch; jangan masukkan ke konfigurasi frontend, contoh, atau paket instalasi aplikasi.
  • Setiap permintaan membawa X-Launch-Key-Id, X-Launch-Timestamp, X-Launch-Nonce, dan X-Launch-Signature.
  • Stempel waktu berupa detik Unix desimal. nonce adalah nilai acak minimal 128 bit yang dikodekan dalam base64url tanpa padding; buat nilai baru untuk setiap percobaan jaringan.

Masukan tanda tangan adalah byte UTF-8 dari tujuh unsur berikut yang digabungkan dengan satu karakter baris baru, tanpa baris baru di akhir:

v1
<key_id>
<timestamp>
<nonce>
<UPPERCASE HTTP method>
<encoded request path and raw query, including the base_url path prefix>
<lowercase hexadecimal SHA-256 digest of the exact request body>

X-Launch-Signature adalah v1= diikuti hasil HMAC-SHA256 yang dikodekan dalam base64url tanpa padding. Isi permintaan GET kosong. Penerima memverifikasi tanda tangan dan rentang waktu sebelum deserialisasi; gunakan perbandingan waktu konstan, izinkan selisih plus atau minus 300 detik secara default, dan simpan nonce setidaknya 600 detik untuk mencegah replay. Jangan gunakan kembali nonce antarpercobaan, tetapi ID peristiwa dan isi permintaan bisnis harus tetap sama.

Tanda tangan tidak menggantikan HTTPS. Permintaan tidak membawa kata sandi pelanggan, kunci pembayaran, atau kunci administrasi Licentivo; secara default hanya referensi akun anonim yang dikirim, bukan email. Klien HTTP server memerlukan batas waktu, batas panjang respons, dan larangan mengikuti pengalihan dengan membawa kredensial. Validasi alamat tujuan saat mengonfigurasi alamat kustom; akses ke jaringan internal harus menjadi kemampuan deployment yang dikonfigurasi secara eksplisit oleh administrator.

4.2 Pemeriksaan kemampuan

GET /launch/v1/capabilities mengembalikan HTTP 200, misalnya:

{
  "data": {
    "protocol": "launch-external-licensing-v1",
    "connection_ref": "merchant-01-sandbox",
    "environment": "sandbox",
    "purchase_types": ["perpetual", "fixed_term"],
    "delivery_types": ["license_key", "activation_url", "instructions"],
    "devices": false,
    "identity_exchange": false
  },
  "request_id": "check-001"
}

protocol, connection_ref, environment, purchase_types, dan delivery_types wajib diisi. Dua yang terakhir harus berupa array tidak kosong; jenis pembelian yang tidak didukung tidak boleh diterbitkan untuk dijual. Pada versi pertama, devices dan identity_exchange harus false; dukungan hanya boleh dinyatakan setelah kontrak ekstensi dan implementasinya selesai.

4.3 Snapshot pembelian

Contoh permintaan POST /launch/v1/events:

{
  "schema": "launch-external-licensing-v1",
  "event_id": "7bf84b91-2749-4b01-a6a7-bd527c488ee8",
  "connection_ref": "merchant-01-sandbox",
  "environment": "sandbox",
  "type": "entitlement.snapshot",
  "change_reason": "purchase",
  "account_ref": "customer_opaque_001",
  "entitlement_ref": "purchase_opaque_001",
  "launch_product_id": "c6dd463e-50f7-4b76-8239-0a8ec6fc304b",
  "launch_plan_version_id": "5459a073-9362-4b46-949d-9b0c5d84421a",
  "product_ref": "desktop-editor",
  "plan_ref": "professional-yearly-v1",
  "version": 1,
  "desired_state": "active",
  "valid_from": "2026-10-25T00:00:00Z",
  "valid_until": "2027-10-25T00:00:00Z"
}

Semua bidang pada contoh di atas wajib diisi. valid_until bernilai null berarti pembelian permanen; nilai lainnya harus lebih akhir daripada valid_from.

Bidang Batasan dan arti
event_id UUID yang dibuat oleh Launch; tetap sama pada percobaan ulang peristiwa yang sama
connection_ref / environment Harus sesuai dengan koneksi dan lingkungan pemilik kunci penandatanganan
account_ref Referensi akun anonim yang stabil; penerima mengidentifikasi pelanggan berdasarkan kombinasi koneksi, lingkungan, dan referensi ini
entitlement_ref Referensi stabil untuk satu hubungan pembelian; pembelian ulang setelah seluruhnya dicabut menggunakan referensi baru
launch_product_id / launch_plan_version_id UUID produk Launch dan versi paket yang tidak dapat diubah
product_ref / plan_ref Referensi eksternal yang dikonfigurasi integrator; 1–128 karakter ASCII, dengan huruf, angka, _, -, dan . diperbolehkan; paket eksternal tidak dibuat secara otomatis
version Versi tujuan yang meningkat secara monoton untuk koneksi, lingkungan, dan referensi pembelian yang sama
desired_state active、suspended、expired、revoked
change_reason purchase、renewal、upgrade、refund、reversal、suspension、resumption、expiry、reconciliation

account_ref dan entitlement_ref menggunakan 1–128 huruf, angka, garis bawah, atau tanda hubung. schema dan type tetap menggunakan nilai dalam contoh. Penerima menerapkan hasil berdasarkan desired_state dan masa berlaku absolut lengkap, tanpa menambahkan hari atau mencabut seluruh lisensi sendiri berdasarkan alasan.

Khusus untuk pengembalian dana: setelah pesanan perpanjangan atau peningkatan dikembalikan, pembelian dasar yang valid mungkin masih ada. Dalam hal ini snapshot masih dapat berstatus active, tetapi masa berlaku dipersingkat atau paket berubah. Status penghentian yang sesuai hanya dikirim jika penghitungan ulang ledger menunjukkan tidak ada lagi cakupan pembelian yang valid.

4.4 Penerimaan, tanda terima, dan pemulihan

Penerima harus menyimpan ID peristiwa, digest isi permintaan asli, dan tugas yang akan dijalankan secara persisten sebelum mengembalikan HTTP 202; permintaan duplikat yang sudah selesai disinkronkan dapat mengembalikan HTTP 200. Keduanya mengembalikan struktur tanda terima berikut.

{
  "data": {
    "event_id": "7bf84b91-2749-4b01-a6a7-bd527c488ee8",
    "connection_ref": "merchant-01-sandbox",
    "environment": "sandbox",
    "entitlement_ref": "purchase_opaque_001",
    "version": 1,
    "payload_sha256": "<64-character lowercase hexadecimal SHA-256 digest of the exact event body>",
    "status": "pending",
    "error_code": null
  },
  "request_id": "receipt-001"
}

Placeholder digest harus diganti dengan digest sebenarnya. Semua bidang tanda terima di atas wajib diisi; error_code bernilai null jika tidak ada kesalahan. Kueri GET /launch/v1/events/{event_id} mengembalikan struktur yang sama dengan HTTP 200; statusnya dapat berupa:

status Arti Penanganan oleh Launch
pending Sudah disimpan secara persisten, tetapi perubahan lisensi sebenarnya belum selesai Periksa kembali nanti; jangan tandai sinkronisasi sebagai selesai
applied Layanan lisensi mengonfirmasi bahwa status tujuan telah benar-benar diterapkan Konfirmasikan sinkronisasi selesai setelah memeriksa semua bidang terkait dan digest
rejected Dipastikan tidak dapat diterapkan, misalnya paket eksternal tidak ada Hentikan percobaan ulang otomatis dan tampilkan kesalahan yang jelas
manual_review Hasil tidak pasti atau status bertentangan dan memerlukan pemeriksaan manual Pertahankan tugas dan peristiwa asli sambil menunggu penanganan yang dapat diaudit

Status penyampaian terpisah dari tanda terima sinkronisasi; applied tidak dapat langsung dianggap sebagai izin menjalankan aplikasi pelanggan.

Persyaratan keandalan:

  • Pengiriman setidaknya sekali; penerima harus menjamin idempotensi bisnis. Tidak dapat dijanjikan bahwa jaringan ‘hanya memanggil sekali’.
  • ID peristiwa yang sama dengan isi permintaan asli yang sama mengembalikan hasil yang sudah ada; ID yang sama dengan isi berbeda mengembalikan HTTP 409 IDEMPOTENCY_CONFLICT.
  • Versi lama tidak boleh menimpa versi baru. Peristiwa atau tujuan yang berbeda untuk versi pembelian yang sama tidak boleh diterima secara diam-diam; kembalikan HTTP 409 STATE_VERSION_CONFLICT untuk pemeriksaan.
  • Setelah respons POST hilang atau proses dimulai ulang, Launch terlebih dahulu melakukan GET terhadap peristiwa asli; kirim ulang ID dan isi permintaan asli hanya setelah EVENT_NOT_FOUND dikembalikan secara jelas.
  • Ketika hasil penerbitan aktual di sistem jarak jauh tidak pasti, integrator juga harus memeriksanya menggunakan referensi idempotensi persisten miliknya; pengiriman ulang tidak boleh menghasilkan lisensi baru lagi.
  • HTTP 429 mengikuti Retry-After; timeout dan 5xx dipulihkan dengan backoff; setelah batas terlampaui, lakukan pemeriksaan manual. Penolakan autentikasi, konfigurasi, dan bisnis tidak boleh dianggap sebagai sinkronisasi berhasil.

Kode kesalahan yang disarankan: SIGNATURE_INVALID (401), SIGNATURE_EXPIRED (401), NONCE_REPLAYED (409), SCOPE_MISMATCH (403), EVENT_NOT_FOUND (404), IDEMPOTENCY_CONFLICT (409), STATE_VERSION_CONFLICT (409), PLAN_UNKNOWN (422), PURCHASE_TYPE_UNSUPPORTED (422), RATE_LIMITED (429), SERVICE_UNAVAILABLE (503). Pesan kesalahan tidak boleh berisi kredensial.

4.5 Penyampaian lisensi

GET /launch/v1/entitlements/{entitlement_ref}/delivery hanya dapat membaca hasil penyampaian yang sudah ada pada koneksi dan lingkungan tersebut; kueri tidak boleh dianggap sebagai perintah penerbitan baru. Contoh HTTP 200:

{
  "data": {
    "connection_ref": "merchant-01-sandbox",
    "environment": "sandbox",
    "entitlement_ref": "purchase_opaque_001",
    "version": 1,
    "status": "ready",
    "delivery": {
      "type": "license_key",
      "value": "EXAMPLE-ONLY-NOT-A-REAL-LICENSE",
      "expires_at": null
    }
  },
  "request_id": "delivery-001"
}

status adalah pending, ready, atau unavailable; ketika bukan ready, delivery adalah null. Ketika ready, type harus berupa license_key, activation_url, atau instructions yang sudah dinyatakan, value maksimal 4096 byte UTF-8, dan expires_at adalah waktu UTC atau null. Semua bidang terkait dalam respons harus sesuai dengan versi pembelian Launch saat ini; penyampaian versi lama tidak dapat dianggap sebagai hasil saat ini.

Kode lisensi adalah data sensitif; respons penyampaian menggunakan Cache-Control: no-store, isi respons tidak dicatat, dan penyimpanan terenkripsi digunakan bila persistensi diperlukan. URL aktivasi hanya menerima origin HTTPS yang diizinkan oleh konfigurasi koneksi; instructions ditampilkan sebagai teks biasa tanpa menjalankan HTML atau skrip. Akun yang dicabut, dikembalikan dananya secara penuh, atau tidak memiliki pembelian valid tidak dapat terus memperoleh informasi penyampaian melalui Launch; pembatalan aktual kredensial yang telah disampaikan dilakukan oleh sistem eksternal.

API administrasi dan pelanggan Launch

Endpoint ini berada di origin Launch yang di-deploy oleh pedagang dan tidak menggunakan kunci HMAC layanan eksternal untuk autentikasi. Administrator menggunakan sesi situs yang ada; permintaan tulis harus membawa X-CSRF-Token. Pelanggan hanya dapat membaca pembeliannya sendiri.

Metode dan path Tujuan
GET /api/v1/admin/licensing/connections Mengembalikan connections, bindings, mappings, dan default_provider; daftar koneksi hanya berisi koneksi kustom, sedangkan Licentivo tetap menggunakan endpoint administrasi sebelumnya
POST /api/v1/admin/licensing/connections Memvalidasi dan menambahkan koneksi kustom
PUT /api/v1/admin/licensing/connections/{id} Mengedit nama, origin aktivasi yang diizinkan, dan konfigurasi tanda tangan; alamat penerimaan historis tetap tidak berubah
POST /api/v1/admin/licensing/connections/{id}/check Memeriksa ulang; last_check_error bukan null dalam HTTP 200 berarti pemeriksaan gagal
PUT /api/v1/admin/products/{id}/licensing Mengonfigurasi penyedia, koneksi, dan pemetaan paket eksternal untuk lingkungan yang dipilih pada produk
GET /api/v1/me/products/{id}/delivery?environment=sandbox Pelanggan saat ini membaca penyampaian lisensi untuk pembelian kustom yang saat ini valid; autentikasi Cookie atau desktop Bearer
GET /api/v1/licensing/documentation Dokumen ini, tanpa perlu masuk
GET /api/v1/licensing/protocol OpenAPI yang harus diimplementasikan oleh layanan kustom, tanpa perlu masuk

Isi permintaan untuk menambahkan koneksi kustom:

{
  "provider": "custom_http",
  "name": "My licensing service",
  "base_url": "https://licenses.example.com",
  "environment": "sandbox",
  "connection_ref": "merchant-01-sandbox",
  "key_id": "key-1",
  "signing_key": "<standard Base64 encoding of 32 to 128 random bytes>",
  "allow_private_network": false,
  "allow_local_http": false,
  "activation_origins": ["https://activate.example.com"]
}

Respons data adalah objek koneksi yang telah disamarkan dan tidak mengembalikan kunci penandatanganan atau secret ID. allow_local_http hanya mengizinkan alamat localhost/loopback di sandbox; HTTPS jaringan privat memerlukan izin eksplisit administrator. Kunci boleh dikosongkan hanya saat mengedit koneksi yang sudah ada. Licentivo tetap diatur melalui POST /api/v1/admin/connections/licentivo.

Isi permintaan untuk mengonfigurasi produk:

{
  "provider": "custom_http",
  "environment": "sandbox",
  "connection_id": "<id returned when creating the connection>",
  "mappings": [
    {
      "version_id": "<Launch plan version UUID>",
      "product_ref": "desktop-editor",
      "plan_ref": "professional-yearly-v1"
    }
  ]
}

Saat memilih Licentivo, kirim {"provider":"licentivo","environment":"sandbox","mappings":[]}; pemetaan produk/kebijakannya tetap menggunakan endpoint sebelumnya. Pergantian pertama mengubah publikasi yang ada menjadi pratinjau dan perlu diperiksa serta diterbitkan ulang menurut penyedia baru. mappings dapat hanya berisi versi yang akan ditambahkan atau dipertahankan; penghilangan tidak menghapus pemetaan lama.

Penyampaian kepada pelanggan menggunakan envelope data standar dengan HTTP 200; tidak ada pembelian mengembalikan 404, produk Licentivo mengembalikan 409 LICENSING_DELIVERY_UNSUPPORTED, belum tersinkronisasi, ditangguhkan, kedaluwarsa, atau dikembalikan dananya secara penuh mengembalikan 409 ENTITLEMENT_NOT_READY, dan ketidaktersediaan sementara layanan eksternal atau tanda terima yang tidak cocok mengembalikan 503. ‘Lihat penyampaian lisensi’ di pusat pelanggan memvalidasi ulang kepemilikan dan status, serta tidak menulis kredensial ke URL atau log.

Endpoint identity, device, integration-check Licentivo untuk produk kustom mengembalikan 409 CUSTOM_LICENSING_SDK_REQUIRED. /credential lama tetap mengembalikan 410. Aplikasi harus menggunakan SDK milik pedagang, bukan menganggap status ready Launch sebagai lisensi saat berjalan.

Contoh dan penerimaan

Contoh adaptor tipis Python menyediakan kerangka penerima untuk tanda tangan, nonce, deduplikasi peristiwa, dan persistensi tanda terima; pemrosesan lisensi sebenarnya perlu diintegrasikan dengan sistem pedagang.

OpenAPI protokol kustom dan OpenAPI Launch masing-masing menjelaskan dua arah tersebut. Penerima tidak perlu mengimplementasikan katalog produk, katalog kebijakan, atau endpoint kepercayaan identitas Licentivo.

Verifikasi lokal menggunakan MySQL terisolasi, adaptor HTTP nyata, dan layanan lisensi/pembayaran simulasi, mencakup respons hilang, mulai ulang, perpanjangan, peningkatan, pengembalian dana, penonaktifan akun, tanda terima tidak cocok, dan isolasi penyampaian. Penerimaan produksi juga memerlukan layanan lisensi dan aplikasi milik pedagang. Kemampuan perangkat, login akun bersama, dan offline yang tidak dinyatakan tidak disediakan oleh Launch.