---
title: Authentication - SNAP
slug: nicepay-api-snap-authentication
description: Informasi tentang API SNAP Authentication yang disediakan oleh NICEPAY
icon: {"faIcon":"fa-solid fa-user-gear"}
createdAt: 2023-06-02T03:48:56.000Z
---

# Tentang Authentication - SNAP

***

NICEPAY menerapkan dua mekanisme keamanan autentikasi pada seluruh API SNAP dengan mengacu pada standar internasional yang berlaku, yakni:

1. **Access Token**, untuk memastikan pemanggil API telah terautentikasi dan berwenang.
2. **Signature**, untuk memastikan keaslian pengirim dan bahwa isi request tidak berubah selama proses komunikasi API.

Tahapan implementasi dari kedua autentikasi standar tersebut akan dijelaskan secara rinci pada halaman ini; mulai dari cara mendapatkan Access Token, sampai pada proses pembuatan Signature untuk menjalankan proses transaksi dengan NICEPAY.



## Informasi Penting

| **Komponen**                 | **Fungsi**                                                                                                      | **Dibuat oleh**                                                   |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| **Client ID / X-CLIENT-KEY** | Identitas milik Merchant yang diberikan oleh NICEPAY                                                            | NICEPAY                                                           |
| **Access Token**             | Otorisasi untuk mengakses NICEPAY  *protected resources*. Berlaku selama 15 menit.                              | NICEPAY <br />(Merchant perlu melakukan request terlebih dahulu). |
| **Signature (X-SIGNATURE)**  | Memastikan integritas data dan *non-repudiation* terjaga saat proses komunikasi dengan API sedang berlangsung.  | Merchant                                                          |



## Alur

1. Merchant membuat Signature terlebih dahulu. Lalu, melakukan *request&#x20;*&#x41;ccess Token.
2. NICEPAY melakukan verifikasi Signature, kemudian melakukan *return&#x20;*`accessToken`.
3. Merchant menggunakan `accessToken (Bearer)` pada *request&#x20;*&#x41;PI SNAP berikutnya; seperti pada pembayaran, periksa status transaksi, dan refund.
4. Jika Access Token yang digunakan telah kedaluwarsa, Merchant perlu mengajukan kembali Access Token yang baru.



# Persiapan Integrasi

***

Sebelum memulai tahap berikutnya, mohon pastikan Merchant sudah memiliki beberapa hal berikut.

- **Client ID** dari NICEPAY. Value ini akan dipakai sebagai header di parameter **`X-CLIENT-KEY`**.&#x20;
- **Pasangan kunci RSA** (Private Key dan Public Key). Private Key hanya disimpan oleh Merchant, sedangkan Public Key didaftarkan kepada NICEPAY.
- Waktu server yang akurat (sinkron NTP), karena `X-TIMESTAMP` akan ikut divalidasi.

:::hint{type="danger"}
**Jangan pernah mengirim, menyimpan di *repository*, atau pun menaruh Private Key di aplikasi Anda (*browser&#x20;*&#x6D;aupun aplikasi *mobile*).&#x20;**

Seluruh pembuatan Signature harus dilakukan pada **server milik Merchant**.
:::

::::hint{type="info"}
:::Iframe{iframeHeight="0" code="Apabila sudah terdaftar sebagai Merchant NICEPAY namun belum memiliki Kredensial SNAP, harap segera hubungi PIC <a style=&#x22;color:blue; text-decoration-line:underline&#x22; href=&#x22;mailto:integration@nicepay.co.id&#x22;>IT Integrasi NICEPAY</a> atau Tim <a style=&#x22;color:blue; text-decoration-line:underline&#x22; href=&#x22;mailto:cs@nicepay.co.id&#x22;>Customer Service NICEPAY</a> agar dapat melakukan proses integrasi API SNAP."}

:::
::::



# NICEPAY Base URL

***

NICEPAY menyediakan dua environment yang bisa diakses oleh Merchant, yaitu Sandbox/Development dan Production. Semua *request* yang dilakukan harus menggunakan HTTPS dengan menambahkan path endpoint setelah base URL dimasukkan. Pastikan Client ID dan Key yang Merchant gunakan sesuai dengan environment yang dituju.

| **Environment** | **Protocol** | **Current NICEPAY Base URL** | **New NICEPAY Base URL**              |
| --------------- | ------------ | ---------------------------- | ------------------------------------- |
| Development     | HTTPS        | `https://dev.nicepay.co.id/` | `https://dev-services.nicepay.co.id/` |
| Production      | HTTPS        | `https://www.nicepay.co.id/` | `https://services.nicepay.co.id/`     |

:::hint{type="warning"}
**Mohon segera lakukan perubahan NICEPAY Base URL menjadi URL terbaru sebelum tanggal 25 Desember 2026.**
:::



# Kredensial untuk Testing

***

Apabila ingin melakukan uji coba API SNAP NICEPAY terlebih dahulu sebelum memulai proses integrasi, silakan gunakan kredensial di bawah ini dengan menggunakan `clientID` **IONPAYTEST**.

:::hint{type="warning"}
Kredensial sandbox ini dipakai bersama dan private key-nya bersifat publik. Mohon hanya digunakan pada **Environment Development**.&#x20;

Jangan pernah digunakan pada environment Production bahkan sebagai **key pair sendiri**.
:::

| **Kredensial**               | **Fungsi**                                                                                                          | **Dipakai pada**                                                                       | **Asal**                                                                                                                                                                                                  | **Contoh Kredensial Testing di Development**                                                                      |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Client ID**                | Identitas Merchant. <br /><br />Dikirim sebagai `X-CLIENT-KEY` (Access Token) dan `X-PARTNER-ID `(service request). | Semua request.                                                                         | Diberikan oleh NICEPAY.                                                                                                                                                                                   | IONPAYTEST                                                                                                        |
| **Channel ID**               | Identitas channel Merchant, yaitu Client ID ditambah 01.                                                            | Header `CHANNEL-ID` pada service request.                                              | Dibentuk dari Client ID.                                                                                                                                                                                  | IONPAYTEST01                                                                                                      |
| **Client Secret \***         | Kunci `HMAC-SHA512` untuk Symmetric Signature.                                                                      | Service request (Registration, Check Status, Cancel, dan lainnya).                     | Diberikan NICEPAY dan tersedia *field* **Client Secret** di [Merchant Back Office](docId\:VMD8YtiiJqku6H8dRhcS6) .<br /><br />Silakan lihat [Credential Management](docId\:Lsyq6wPnvr6HP0E45gTve)         | Silakan hubungi tim Integrasi NICEPAY untuk mendapatkan kredensial ini.<br /><br />integration\@nicepay.co.id     |
| **Private Key (RSA 2048)**   | Menandatangani Asymmetric Signature.                                                                                | Request Access Token.                                                                  | Dibuat dan disimpan sendiri oleh Merchant.                                                                                                                                                                | Silakan lihat halaman bagian Signature untuk mengetahui cara membuat Private Key.                                 |
| **Public Key (RSA 2048) \*** | Melakukan verifikasi Asymmetric Signature.                                                                          | Didaftarkan ke NICEPAY.                                                                | Dibuat bersama Private Key, lalu ditempel Merchant dengan value **Merchant Public Key** yang ada pada Merchant Back Office -[Credential Management](docId\:Lsyq6wPnvr6HP0E45gTve) <br />dalam format PEM. | Silakan daftarkan Public Key Merchant dengan menghubungi tim Integrasi NICEPAY melalui integration\@nicepay.co.id |
| **Public Key NICEPAY \***    | Melakukan verifikasi Signature pada notifikasi dari NICEPAY.                                                        | Diperlukan pada saat Merchant melakukan integrasi API Notifikasi SNAP dengan NICEPAY.  | Diberikan oleh NICEPAY melalui email atau bisa dicek pada *field* **NICEPAY Public Key** di Merchant Back Office -[Credential Management](docId\:Lsyq6wPnvr6HP0E45gTve).                                  | Silakan hubungi tim integrasi NICEPAY untuk mendapatkan kredential ini.<br /><br />integration\@nicepay.co.id     |
| **Access Token**             | Otorisasi service request, berlaku selama 15 menit.                                                                 | Header Authorization.                                                                  | Hasil *request* dari Access Token.                                                                                                                                                                        | -                                                                                                                 |

::::hint{type="info"}
:::Iframe{iframeHeight="0" code="<!-- <p>paste iframe code here</p> -->ℹ️ Silakan menghubungi <a style=&#x22;color:blue; text-decoration-line:underline&#x22; href=&#x22;mailto:integration@nicepay.co.id&#x22;>Tim Integrasi NICEPAY</a> untuk informasi lebih lanjut terkait Client Secret, Public Key (RSA 2048), dan NICEPAY Public Key."}

:::
::::

Berikut ini merupakan dua parameter wajib lain yang dibuat oleh sistem Merchant pada setiap *request*, bukan diberikan oleh NICEPAY.

- **X-TIMESTAMP**: waktu saat Merchant melakukan *request* dalam format ISO-8601, zona waktu GMT+7.
- **X-EXTERNAL-ID**: nomor referensi unik untuk setiap *request* transaksi.

Untuk transaksi yang memerlukan notifikasi, seperti Virtual Account, siapkan juga **Notification URL** milik Merchant. URL ini dikirim sebagai `dbProcessUrl` saat menggunakan Registration API.

## Cara Memakai Kredensial Sandbox

1. Simpan private key sandbox yang diberikan oleh tim NICEPAY, lalu buat Asymmetric Signature dengan IONPAYTEST sebagai Client ID.&#x20;
   Contoh lengkap ada pada bagian [Contoh Demo (Asymmetric)](docId\:wd-31XHbZbXhrs4YsXLD8).
2. Hit Request Access Token ke endpoint Development.
3. Setelah Access Token didapatkan, buat Symmetric Signature dengan Client Secret yang diberikan oleh NICEPAY dan taruh *value* Access Token pada header Authorization.
4. Gunakan NICEPAY Public Key untuk melakukan validasi notifikasi yang dikirim NICEPAY.



# Access Token API

***

Access Token adalah *string value* autentikasi yang diberikan oleh NICEPAY ke Merchant untuk mengakses API, seperti pada pembayaran, cek status transaksi, atau pengembalian dana.



## Request Access Token

| **Service Code** | 73                                                                                           |
| ---------------- | -------------------------------------------------------------------------------------------- |
| **API Endpoint** | [`/nicepay/v1.0/access-token/b2b`](https://dev.nicepay.co.id/nicepay/v1.0/access-token/b2b)  |
| **HTTP Method**  | **POST**                                                                                     |
| **Description**  | Request Token for Authentication&#xD;                                                        |
| **Content-type** | `application/json`                                                                           |



## Header

***

### Request Access Token Header

| **Nama Parameter Header** | **Tipe** | **Atribut** | **Konten**                                                                                                                                                                                                                                                       |
| ------------------------- | -------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Content-Type`            | String   | Mandatory   | `Application/json`                                                                                                                                                                                                                                               |
| `X-TIMESTAMP`             | String   | Mandatory   | Waktu request dengan format ISO-8601 beserta zona waktu<br />`YYYY-MM-DDTHH:MM:SS`<br />(2022-03-21T10:11:40+07:00) <br />                                                                                                                                       |
| `X-CLIENT KEY`            | String   | Mandatory   | Nilai Client ID ini disediakan oleh NICEPAY. Pastikan untuk menggunakan nilai tersebut dengan benar. <br /><br />(`X-CLIENT `<br />`KEY` = `CLIENT_ID`)                                                                                                          |
| `X-SIGNATURE`             | String   | Mandatory   | Dibuat oleh Merchant  menggunakan algoritma Asymmetric Signature SHA256withRSA.<br /><br />(`Private_Key`, `stringToSign`)<br />`stringToSign `= `client ID` + “`\|`” + `X-TIMESTAMP`<br /><br />Lihat bagian [Signature](docId\:wd-31XHbZbXhrs4YsXLD8) berikut. |



## Body

***

### Request Access Token Parameter

| **Parameter**    | **Tipe** | **Kebutuhan** | **Deskripsi**                                                  |
| ---------------- | -------- | ------------- | -------------------------------------------------------------- |
| `grantType`      | String   | Mandatory     | Harap hanya masukkan nilai berikut<br />“`client_credentials`” |
| `additionalInfo` | Object   | Optional      | Informasi tambahan. Boleh dikirim sebagai objek kosong \{}     |

### Response Access Token Parameter

| **Parameter BI**  | **Parameter NICEPAY** | **Tipe** | **Ukuran** | **Kebutuhan** | **Deskripsi**                                                                                                                                                           |
| ----------------- | --------------------- | -------- | ---------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `responseCode`    | `responseCd`          | String   |            | Optional      | [General Response Code and Message - API SNAP](docId\:lKqJXSl5CMKdXYXxHYYSs)<br /><br />Kode error yang mengindikasikan jenis error yang dikembalikan dalam respons API |
| `responseMessage` | `responseMsg`         | String   |            | Optional      | Response Message<br /><br />Memberikan informasi tambahan secara terperinci mengenai respons API                                                                        |
| `accessToken`     |                       | String   | 2048       | Mandatory     | Sebuah *string* yang mewakili otorisasi dikeluarkan oleh NICEPAY untuk Merchant, sehingga dapat digunakan untuk mengakses API transaksi.                                |
| `tokenType`       |                       |   String |            | Mandatory     | Selalu bernilai `Bearer`.                                                                                                                                               |
| `expiresIn`       |                       | String   |            | Mandatory     | Masa berlaku token dalam detik:<br />`900` (15 menit).                                                                                                                  |

### Sample Parameter

:::CodeblockTabs
Sample Request

```json
curl --location 'https://dev-services.nicepay.co.id/nicepay/v1.0/access-token/b2b' \
--header 'Content-Type: application/json' \
--header 'X-CLIENT-KEY: IONPAYTEST' \
--header 'X-TIMESTAMP: 2024-12-31T10:11:40+07:00' \
--header 'X-SIGNATURE: DZ9iZR6xtWoFwFaARgo9h6mDgckZpPRLQjMTAlGqrYrJ4xah/deCsxe159H7sf9i2clJeGrsoq5ZDe4tzM+IRQhcxY47K3mYcbnPFGdP5maCC/tCCi63TScB0XUpJzpuPc4TM3G+2uIo816VcoKTXxR5v188m5yGDsGmfW4urddjI1Xor9lZdXP1c6fMH19psMN0g137GCD4tOdjeKW/gGpbvjMi0HQu9PjaJtoFxGmypdxayXfUU3VxWtSWf6AZ88UQ++iOBXfAQIX5Vtt6+fKh/1DOCEcZFe87Em1437VZcTET5dOuEXeQ+ow2PT/Or9iey0M8qQzk3Y6oWJg/sw==' \
--data '{
    "grantType": "client_credentials",
    "additionalInfo": {}
}'
```

Sample Response

```json
{
    "responseCode": "2007300",
    "responseMessage": "Successful",
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "tokenType": "Bearer",
    "expiresIn": "900"
}
```
:::



## Cara Menggunakan Access Token

Sertakan token pada header Authorization di setiap *request* API SNAP berikutnya.

:::BlockQuote
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
:::

### Expiry Date and Requesting New Access Token

- Token berlaku selama **900 detik (15 menit)** sejak diterbitkan.
- Tidak ada *refresh token*. Setelah kedaluwarsa, mohon minta token baru melalui endpoint yang sama.
- Simpan token di memori atau *cache* server Merchant, lalu pakai ulang sampai mendekati waktu kedaluwarsa. Mohon untuk tidak meminta token baru pada setiap transaksi apabila token *expiry time* masih aktif.
- Jika sebuah *request* transaksi ditolak karena token tidak valid atau kedaluwarsa, silakan melakukan *request* token baru, lalu ulangi *request* transaksi tersebut satu kali.



## API SNAP Service Code

Berikut ini merupakan daftar Service Code terkait layanan yang dapat digunakan Merchant setelah mendapatkan Access Token dari NICEPAY.

| **Metode**      | **Service Code** | **API Reference**                                                                                                                                                                                                                                                                                                                                                                                                                               |
| --------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Virtual Account | `27`             | [Registration - API Virtual Account SNAP](docId\:K4DeuHcQ_4pSto2beLqb7)                                                                                                                                                                                                                                                                                                                                                                         |
| Virtual Account | `26`             | [Check Status Transaction - API Virtual Account SNAP](docId\:xaW0SxwKv9j7b5zLbtVpR)                                                                                                                                                                                                                                                                                                                                                             |
| Virtual Account | `31`             | [Cancel - API Virtual Account SNAP](docId\:vN3l9wxp-CA7deDK7AtM8)                                                                                                                                                                                                                                                                                                                                                                               |
| E-Wallet        | `73`             | [Access Token B2B & B2B2C - Account Binding API E-Wallet (Direct Debit) SNAP](docId\:qZvrZPmasvcazBAKT97SS)                                                                                                                                                                                                                                                                                                                                     |
| E-Wallet        | `54`             | [Registration - API E-Wallet (Direct Debit) SNAP](docId:66iE5aVXXL4uqw6hqFPVV)                                                                                                                                                                                                                                                                                                                                                                  |
| E-Wallet        | `55`             | [Check Status Transaction - API E-Wallet (Direct Debit) SNAP](docId\:vB63D8suaKPYP-4bIOWx9)                                                                                                                                                                                                                                                                                                                                                     |
| E-Wallet        | `58`             | [Refund Transaction - API E-Wallet (Direct Debit) SNAP](docId:8-hlezmJtlz45LRJnXcEc)                                                                                                                                                                                                                                                                                                                                                            |
| QRIS            | `47`             | [Registration - API QRIS SNAP](docId\:n42BapM1t1eOiXNS-RA_d)                                                                                                                                                                                                                                                                                                                                                                                    |
| QRIS            | `51`             | [Check Status Transaction - API QRIS SNAP](docId:3aXWe6p6cyHX_ZuN-bvgQ)                                                                                                                                                                                                                                                                                                                                                                         |
| QRIS            | `78`             | [Refund Transaction - API QRIS SNAP](docId\:U1UpkNC78XEyuHGD4CxPD)                                                                                                                                                                                                                                                                                                                                                                              |
| Payout          | `00`             | - [Registration - API Payout (Disbursement) SNAP](docId\:SgtN0VBKPUWVOV62EVREB)<br />- [Approve Transaction - API Payout (Disbursement) SNAP](docId\:Q5UEc9-eqJxtmhVJtMbV7)<br />- [Reject Transaction - API Payout (Disbursement) SNAP](docId:926778w1tSetC6obRYhwX)<br />- [Cancel Transaction - API Payout (Disbursement) SNAP](docId:25Q_ooJlYAS8krNpg6bb3)<br />- [Inquiry - API Payout (Disbursement) SNAP](docId\:GkYB9CEm1x0EzRv_wCLre) |
| Payout          | `11`             | [Balance Inquiry - API Payout (Disbursement) SNAP](docId\:e-wNhrOEkkZ1Hxiqz7S_5)                                                                                                                                                                                                                                                                                                                                                                |



## Error API yang Sering Ditemui (Access Token)

Berikut ini merupakan penyebab umum kegagalan yang sering terjadi pada saat melakukan request token. Kunjungi halaman [General Response Code and Message - API SNAP](docId\:lKqJXSl5CMKdXYXxHYYSs) untuk informasi lebih lengkap.

| **Case**                   | **Yang perlu diperiksa**                                                    |
| -------------------------- | --------------------------------------------------------------------------- |
| Signature tidak valid      | Format `stringToSign`, Private Key yang dipakai, dan encoding Base64.       |
| `Client ID` tidak dikenali | Nilai `X-CLIENT-KEY` dan environment (Development/Sandbox atau Production). |
| Format `X-TIMESTAMP` salah | Format ISO-8601 dengan zona waktu, misalnya +07:00.                         |
| Field wajib kosong         | Header `X-TIMESTAMP`, `X-CLIENT-KEY`, `X-SIGNATURE`, dan `grantType`.       |
| `grantType` salah          | Harus diisi dengan value "`client_credentials`".                            |



# Signature

***

Signature (`X-SIGNATURE`) adalah digital sign pada setiap *request* di API SNAP. Signature ini memberikan tiga jaminan keamanan, mencakup:

1. **Integritas Data.&#x20;**&#x4D;emastikan data permintaan tidak diubah selama proses pengiriman tanpa terdeteksi oleh sistem. Jika terdapat perubahan pada data, tanda tangan digital tidak lagi valid sehingga permintaan akan ditolak.
2. **Non-Repudiation.** Memastikan pengirim tidak dapat menyangkal permintaan yang telah ditandatangani menggunakan Private Key miliknya, karena tanda tangan tersebut hanya dapat dibuat oleh pihak yang memiliki Private Key yang sesuai. Mekanisme ini berlaku untuk tanda tangan dengan Asymmetric Signature.
3. **Perlindungan Replay.** Mencegah permintaan lama yang telah dicegat untuk dikirim ulang dan diproses kembali sebagai permintaan yang valid. Hal ini dilakukan dengan menyertakan `X-TIMESTAMP` dalam data yang ditandatangani, sehingga validitas waktu permintaan dapat diverifikasi.

Standar SNAP dari Bank Indonesia menggunakan dua jenis Signature bergantung pada API yang dipanggil.

| **Jenis**      | **Dipakai untuk**            | **Algoritma** | **Kunci**             |
| -------------- | ---------------------------- | ------------- | --------------------- |
| **Asymmetric** | Request Access Token.        | SHA256withRSA | Private Key Merchant  |
| **Symmetric**  | Request layanan (transaksi). | HMAC-SHA512   | Client Secret         |



## Create Key Pair for Asymmetric Signature A (Private Key dan Public Key)

Asymmetric Signature menggunakan sepasang kunci RSA yang terdiri dari dua jenis kunci:

- **Private Key:** Digunakan oleh Merchant untuk menandatangani API request. Kunci ini wajib dijaga kerahasiaannya dan tidak boleh dibagikan kepada pihak lain.
- **Public Key:** Diberikan kepada NICEPAY untuk keperluan proses verifikasi Signature.

Kedua kunci tersebut wajib menggunakan panjang kunci **RSA 2048-bit**.

Contoh di bawah ini menggunakan OpenSSL.

**1. Buat Private Key.**

:::BlockQuote
openssl genpkey -algorithm RSA -out private\_key.pem -pkeyopt rsa\_keygen\_bits:2048
:::

File `private_key.pem` berformat PKCS#8 (diawali `-----BEGIN PRIVATE KEY-----`), yang bisa langsung dipakai di Java dan Node.js.

**2. Buat Public Key dari Private Key.**

:::BlockQuote
openssl rsa -in private\_key.pem -pubout -out public\_key.pem
:::

File `public_key.pem` diawali dengan `-----BEGIN PUBLIC KEY-----`.

**3. Serahkan Public Key ke NICEPAY.**

Kirim hanya `public_key.pem` ke NICEPAY. Pastikan Merchant mendaftarkan Public Key untuk environment yang dipakai (Development/Sandbox atau Production). Gunakan format PEM, yaitu isi `public_key.pem` lengkap dengan baris `-----BEGIN PUBLIC KEY-----` dan `-----END PUBLIC KEY-----`. Tempel hanya Public Key. Jangan pernah menempelkan Private Key di *field* mana pun.

**4. Simpan private key dengan aman**

Simpan `private_key.pem` di server Merchant dengan akses terbatas, misalnya di secret manager atau variabel lingkungan yang terlindungi. Jika Private Key bocor, buat key pair baru dan daftarkan Public Key yang baru ke NICEPAY.

**5. Uji pembuatan signature (opsional)**

Merchant bisa mencoba membuat Signature dari terminal untuk membandingkan hasilnya dengan kode yang telah dimiliki.

:::BlockQuote
echo -n "IONPAYTEST|2024-12-31T10:11:40+07:00" | openssl dgst -sha256 -sign private\_key.pem | openssl base64 -A
:::

:::hint{type="info"}
**Catatan format:** Jika Private Key Merchant diawali dengan `  -----BEGIN RSA PRIVATE KEY-----  `(PKCS#1), ubah ke PKCS#8 menjadi `openssl pkcs8 -topk8 -nocrypt -in private_key.pem -out private_key_pkcs8.pem` karena Java umumnya membutuhkan format PKCS#8.
:::

*Command* ini menghasilkan nilai `X-SIGNATURE` untuk `stringToSign` tersebut.



## Signature untuk Access Token (Asymmetric)

**1. Siapkan `stringToSign`.**

:::BlockQuote
stringToSign = X-CLIENT-KEY + "|" + X-TIMESTAMP
:::

Contoh:

:::BlockQuote
IONPAYTEST|2024-12-31T10:11:40+07:00
:::

Nilai `X-TIMESTAMP` pada `stringToSign` harus **identik** dengan yang dikirim di Header.

**2. Tandatangani dengan `SHA256withRSA`.**

Gunakan algoritma `SHA256withRSA` dengan Private Key Merchant untuk menandatangani `stringToSign`.

**3. Encode dengan Base64.**

Hasil *signature* (byte) di-encode ke Base64.

**4. Kirim sebagai Header.**

Masukkan hasilnya ke Header `X-SIGNATURE`.

:::BlockQuote
X-SIGNATURE = Base64( SHA256withRSA( Private\_Key, stringToSign ) )
:::

### Sample Code

:::CodeblockTabs
```java
String stringToSign = clientId + "|" + timestamp;

java.security.Signature signer = java.security.Signature.getInstance("SHA256withRSA");
signer.initSign(privateKey); // java.security.PrivateKey
signer.update(stringToSign.getBytes(java.nio.charset.StandardCharsets.UTF_8));

String xSignature = java.util.Base64.getEncoder().encodeToString(signer.sign());
```

```nodejs
const crypto = require('crypto');
const fs = require('fs');

const clientId = 'IONPAYTEST';
const timestamp = '2024-12-31T10:11:40+07:00'; // sama persis dengan header X-TIMESTAMP

const stringToSign = `${clientId}|${timestamp}`;
const privateKey = fs.readFileSync('private_key.pem', 'utf8');

const signer = crypto.createSign('RSA-SHA256');
signer.update(stringToSign);
signer.end();

const xSignature = signer.sign(privateKey, 'base64');
```
:::

### Contoh Demo (Asymmetric)

Gunakan data demo berikut untuk berlatih dan membandingkan hasil kode Merchant.&#x20;

:::hint{type="warning"}
Key pair di bawah dibuat khusus untuk demo. **Jangan pernah digunakan pada Development/Sandbox atau Production.**
:::

****

**Data input**

:::BlockQuote
X-CLIENT-KEY : IONPAYTEST
X-TIMESTAMP  : 2024-12-31T10:11:40+07:00
:::

**stringToSign**

:::BlockQuote
IONPAYTEST|2024-12-31T10:11:40+07:00
:::

**Private Key demo** (simpan sebagai `ionpaytest_sandbox_private_key.pem`)

:::BlockQuote
\-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDU0njmaK+v6zB5
fE2IvZjvz5TJ0njYWUs8lg6uHNeApLSq6PlM4K9cL//I743bHGfiQ2BIij6W7XPE
dg374SSuNF/cJXzEewMY0kgzxvBvuFMO8tVrsiOX7BM4pAOvgRhFCZo5GxVPkH3o
gVji/uF4JKK8sLE6WYVdM0Rvsuzc2I1nthROf4iPRfOLooWnHtOrByYjGg7kCT+S
koaD4ieEWMRNljlPP/J08Uo1g0Wx+7dY9DA16enfbjjs9m6xtlIq8A8H+tMEnhLl
u77Mxj5bJv8HXVTHrqTigIh8CMR2n2u9LYom1rK+cOgof6J11JPA7lt0/XUfhP1H
iy1DW5GPAgMBAAECggEAFTwG2h554RibVpPDfLBGMS9KDjUU36lRK3NhdZflHK3S
ZPcn4LbOaGlVoSvdwI3+A4JrefFpO0/n7CNHU+lr6oHJSsLmxwfrEC/zCk+AL/V5
PBWYm81DZeYlKNKcl4dO75x8qdP89VpaZbd6MfPydTVak28hz8uc1ebGnkqA/avj
I4WDOT5w81ECXe6SYy1TjHY7Lq2Gaqj79rIKF+tU6HAbKxPDR78vzFi/dpN38OYX
///Db4CU5mcJKBFfHOTE3lUYUZ3/CmfccReHxs0U9Z12mACw/pvyqz3LKslus7X1
Zu25U0YPtmIZ30HTAZ26o06GZDRAta+KeJaYHEMVyQKBgQDrB7Rq79xbaHEs+i0q
duw0w+4KlMtOFOfV/4YTcpDDYO0+beNg6V3nvIAhj8z5dlv2BUxdur7qQpR77Ixa
Th/5pnYmoKLYYAv7bVg54wTmk/rZ1hE+QJpC4Gji2tKUcEpU6Uajv3M2SYqrAPc8
r+Fhbgu+LPhknjPfflhP+7kmXQKBgQDnz4S+rTlY2i12UEbLcLpJBDvs+KZTzx1l
C6s1uL6gKfUcR6TQ0ndMZI/cDsro0UC+JuqsQrahOS2JM9YgM6wzXEVX6dE9OIVz
yYIPpY/d9Lnl8pF2Hpdd7d99hIfVs2MtvBgP5xRxhDbWkXHWRbS0JJCRggOyll6d
6vt6tNrA2wKBgQCQ5rYn++u6e2DTXwZ7mMg2G9nlsijJ4f+xIxGxab+whVCfXbaC
6D3aApBooLS51GwL+OZFHz5XRWcwI/3AK0xxaVyMohrkFgstHxP21G0QD4nnxZ/p
5oB03NAtlMWheL2LLis8B2vru1l/5l+HjdQBcoxQ2n7l4dePYeDmpwZWjQKBgEey
aY5IKYqPwKvtXFgj/5oB0z8SEO+vCZptJ4EwKNWE5Kjgh9uGnRtlpxEbCitEPVAS
3VZ2M+JduvXKsJm5IbOpAFGWof7bcntDghSw0nSF8tFqWw87mvmUTyGVUiYIm85T
dOXGRQ5vJD7tMVZirOdiv8wheF9OHumc+jcTpO0tAoGAcm/z+EqWfzeIV/6kQF3x
DZUOzC+XyoF7PI844JK7FZY9Al0cS2RkFEkrvGTjGqXIyYqv1kL5uc9CWCxR8Adf
UFxginBS+0bEgjlW0J0dPwCdSzdT+vBvodw2GPdCVBAkyS/KmYckv6pOuHufXUUv
PXxg91vzYHpJYLnNn9h+VNI=
\-----END PRIVATE KEY-----
:::

**Public Key demo** (simpan sebagai `ionpaytest_sandbox_public_key.pem`)

:::BlockQuote
\-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1NJ45mivr+sweXxNiL2Y
78+UydJ42FlLPJYOrhzXgKS0quj5TOCvXC//yO+N2xxn4kNgSIo+lu1zxHYN++Ek
rjRf3CV8xHsDGNJIM8bwb7hTDvLVa7Ijl+wTOKQDr4EYRQmaORsVT5B96IFY4v7h
eCSivLCxOlmFXTNEb7Ls3NiNZ7YUTn+Ij0Xzi6KFpx7TqwcmIxoO5Ak/kpKGg+In
hFjETZY5Tz/ydPFKNYNFsfu3WPQwNenp32447PZusbZSKvAPB/rTBJ4S5bu+zMY+
Wyb/B11Ux66k4oCIfAjEdp9rvS2KJtayvnDoKH+iddSTwO5bdP11H4T9R4stQ1uR
jwIDAQAB
\-----END PUBLIC KEY-----
:::

**Hasil: X-SIGNATURE**

:::BlockQuote
DZ9iZR6xtWoFwFaARgo9h6mDgckZpPRLQjMTAlGqrYrJ4xah/deCsxe159H7sf9i2clJeGrsoq5ZDe4tzM+IRQhcxY47K3mYcbnPFGdP5maCC/tCCi63TScB0XUpJzpuPc4TM3G+2uIo816VcoKTXxR5v188m5yGDsGmfW4urddjI1Xor9lZdXP1c6fMH19psMN0g137GCD4tOdjeKW/gGpbvjMi0HQu9PjaJtoFxGmypdxayXfUU3VxWtSWf6AZ88UQ++iOBXfAQIX5Vtt6+fKh/1DOCEcZFe87Em1437VZcTET5dOuEXeQ+ow2PT/Or9iey0M8qQzk3Y6oWJg/sw==
:::

Karena `SHA256withRSA` (PKCS#1 v1.5) menghasilkan nilai Signature yang sama untuk input dan key yang sama, pengujian yang dilakukan oleh Merchant seharusnya menghasilkan Signature yang identik dengan contoh di atas. Merchant juga dapat melakukan verifikasi melalui terminal:

:::BlockQuote
printf '%s' "IONPAYTEST|2024-12-31T10:11:40+07:00" | openssl dgst -sha256 -sign ionpaytest\_sandbox\_private\_key.pem | openssl base64 -A
:::



## Client Secret (Symmetric Key)

Berbeda dengan RSA Key Pair, kunci untuk Symmetric Signature **tidak dibuat sendiri oleh Merchant**. Kunci tersebut merupakan **Client Secret** yang diterbitkan oleh NICEPAY dan digunakan sebagai key untuk algoritma HMAC-SHA512. NICEPAY memakai key yang sama untuk melakukan verifikasi terhadap Signature yang dihasilkan Merchant.

| ****                          | **Asymmetric (Access Token)** | **Symmetric (Request Layanan)**                         |
| ----------------------------- | ----------------------------- | ------------------------------------------------------- |
| **Kunci**                     | Private Key RSA               | Client Secret                                           |
| **Dibuat oleh**               | Merchant                      | NICEPAY                                                 |
| **Yang diberikan ke NICEPAY** | Public Key                    | Tidak ada, key tidak boleh dikirim kepada pihak manapun |
| **Disimpan oleh**             | Merchant (Private Key)        | Merchant dan NICEPAY                                    |

Panduan Pengelolaan Client Secret:

- Simpan Client Secret di server Merchant menggunakan *secret manager* atau *environment variables* yang terlindungi.
- Jangan menyimpan Client Secret di dalam *source code*, repository, atau aplikasi disisi klien, termasuk browser dan aplikasi mobile.
- Jangan menyertakan Client Secret dalam request, log, maupun pesan atau komunikasi kepada pihak mana pun, termasuk Tim NICEPAY.
- Gunakan Client Secret yang sesuai dengan environment, baik Development/Sandbox maupun Production.
- Jika Client Secret terindikasi bocor atau terekspos, segera hubungi tim NICEPAY untuk meminta penerbitan Client Secret baru.



## Signature untuk Request Layanan Transaksi (Symmetric)

Setelah memperoleh **Access Token**, Merchant dapat mengajukan *request* layanan transaksi SNAP NICEPAY (misalnya registrasi transaksi, pembayaran, periksa status, dan pengembalian dana). Setiap request wajib ditandatangani menggunakan **Symmetric Signature**.&#x20;

Berikut adalah header yang wajib disertakan dalam request :

| **Nama Header** | **Kebutuhan** | **Deskripsi**                                                                                                        |
| --------------- | ------------- | -------------------------------------------------------------------------------------------------------------------- |
| Content-Type    | Mandatory     | `application/json`                                                                                                   |
| Authorization   | Mandatory     | Bearer &#x7B;accessToken}                                                                                            |
| X-TIMESTAMP     | Mandatory     | Waktu request, format ISO-8601 dalam zona waktu GMT+7 (Jakarta). <br /><br />Contoh: `2024-12-31T10:11:40+07:00`     |
| X-SIGNATURE     | Mandatory     | Symmetric Signature yang dibuat Merchant, dengan rumus di bawah.                                                     |
| X-PARTNER-ID    | Mandatory     | Client ID dari NICEPAY. <br /><br />Maksimal 20 karakter.                                                            |
| X-EXTERNAL-ID   | Mandatory     | Nomor referensi unik untuk setiap *request*. <br /><br />Maksimal 40 karakter.                                       |
| CHANNEL-ID      | Mandatory     | "Client ID" ditambah "01". <br /><br />Contoh: IONPAYTEST + 01 menjadi IONPAYTEST01<br /><br />Maksimal 20 karakter. |

**1. Hitung hash body**

Minify body request dengan hapus spasi dan garis baris baru di luar nilai string, hitung SHA-256, lalu ubah ke heksadesimal huruf kecil.

:::BlockQuote
bodyHash = LowerCase( HexEncode( SHA-256( Minify( RequestBody ) ) ) )
:::

**2. Susun stringToSign**

:::BlockQuote
stringToSign = HTTPMethod + ":" + EndpointUrl + ":" + AccessToken + ":" + bodyHash + ":" + X-TIMESTAMP
:::

`EndpointUrl` merujuk pada nilai **API Endpoint** yang tercantum pada setiap halaman dokumentasi API. Sertakan query string jika tersedia, tetapi tidak termasuk domain..

Contoh: `/api/v1.0/transfer-va/create-va` untuk [Registration - API Virtual Account SNAP](docId\:K4DeuHcQ_4pSto2beLqb7).&#x20;

**3. Sign dengan HMAC-SHA512**

:::BlockQuote
X-SIGNATURE = Base64( HMAC-SHA512( clientSecret, stringToSign ) )
:::

### Sample Code

:::CodeblockTabs
```java
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

// requestBody = body JSON yang sudah di-minify, sama persis dengan yang dikirim
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] hash = sha256.digest(requestBody.getBytes(StandardCharsets.UTF_8));

StringBuilder hex = new StringBuilder();
for (byte b : hash) {
    hex.append(String.format("%02x", b)); // huruf kecil
}
String bodyHash = hex.toString();

String stringToSign = httpMethod + ":" + endpointUrl + ":" + accessToken
        + ":" + bodyHash + ":" + timestamp;

Mac mac = Mac.getInstance("HmacSHA512");
mac.init(new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA512"));

String xSignature = Base64.getEncoder()
        .encodeToString(mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)));
```

```nodejs
const crypto = require('crypto');

const body = JSON.stringify(requestBody); // JSON.stringify sudah menghasilkan body ter-minify
const bodyHash = crypto.createHash('sha256').update(body).digest('hex').toLowerCase();

const stringToSign = [method, endpointUrl, accessToken, bodyHash, timestamp].join(':');

const xSignature = crypto
  .createHmac('sha512', clientSecret)
  .update(stringToSign)
  .digest('base64');
```
:::

Body yang di-hash harus **sama persis** dengan body yang dikirim. Jika library yang dipakai Merchant untuk mengirim request rupanya mengubah urutan atau format JSON setelah Signature dibuat, maka proses verifikasi akan gagal.

### Contoh Demo (Symmetric)

Contoh berikut ini menggunakan [Registration - API Virtual Account SNAP](docId\:K4DeuHcQ_4pSto2beLqb7) (Service Code `27`, Bank BMRI), dengan Client Secret dan Access Token demo. **Jangan memakai nilai demo ini** untuk *request&#x20;*&#x73;ungguhan pada environment Development maupun Production.

**Data input**

:::BlockQuote
HTTP Method   : POST
EndpointUrl   : /api/v1.0/transfer-va/create-va
AccessToken   : DEMO\_ACCESS\_TOKEN\_0123456789
X-TIMESTAMP   : 2024-12-31T10:11:40+07:00
Client Secret : DEMO\_CLIENT\_SECRET\_0123456789
:::

**Request body (sudah di-minify)**

:::BlockQuote
\{"partnerServiceId":"","customerNo":"","virtualAccountNo":"","virtualAccountName":"Jhon Doe","trxId":"2022020100000000000001","totalAmount":\{"value":"10000.00","currency":"IDR"},"additionalInfo":\{"bankCd":"BMRI","goodsNm":"Jhon Doe","dbProcessUrl":"https\://dev-services.nicepay.co.id/IONPAY\_CLIENT/paymentResult.jsp"}}
:::

**1. bodyHash**

:::BlockQuote
349290ab6d7077f53cf2904fab16b673900c336d8d24cdf2b3d520adbf89cc15
:::

**2. stringToSign**

:::BlockQuote
POST:/api/v1.0/transfer-va/create-va\:DEMO\_ACCESS\_TOKEN\_0123456789:349290ab6d7077f53cf2904fab16b673900c336d8d24cdf2b3d520adbf89cc15:2024-12-31T10:11:40+07:00
:::

**3. Hasil: X-SIGNATURE**

:::BlockQuote
mopZ9NrDMwSN1+06feyghmH+b01rZI185o9lnheWC22hS84om3MQUTaLN7+1mpdPuAcqddd8JAxP/8OOKnMD4w==
:::

**4. Sertakan Signature dalam Request**

Signature yang telah dihasilkan wajib disertakan pada header `X-SIGNATURE`, bersama dengan header wajib lainnya sebagaimana tercantum pada tabel di atas.

:::BlockQuote
curl --location 'https\://dev-services.nicepay.co.id/nicepay/api/v1.0/transfer-va/create-va' \\
\--header 'Content-Type: application/json' \\
\--header 'Authorization: Bearer DEMO\_ACCESS\_TOKEN\_0123456789' \\
\--header 'X-TIMESTAMP: 2024-12-31T10:11:40+07:00' \\
\--header 'X-SIGNATURE: mopZ9NrDMwSN1+06feyghmH+b01rZI185o9lnheWC22hS84om3MQUTaLN7+1mpdPuAcqddd8JAxP/8OOKnMD4w==' \\
\--header 'X-PARTNER-ID: IONPAYTEST' \\
\--header 'X-EXTERNAL-ID: tXid202410142300021707638093' \\
\--header 'CHANNEL-ID: IONPAYTEST01' \\
\--data-raw '\{"partnerServiceId":"","customerNo":"","virtualAccountNo":"","virtualAccountName":"Jhon Doe","trxId":"2022020100000000000001","totalAmount":\{"value":"10000.00","currency":"IDR"},"additionalInfo":\{"bankCd":"BMRI","goodsNm":"Jhon Doe","dbProcessUrl":"https\://dev-services.nicepay.co.id/IONPAY\_CLIENT/paymentResult.jsp"}}'
:::

:::hint{type="info"}
**Catatan Penting:**

- Request body yang dikirim melalui `--data-raw` harus sama persis dengan request body yang digunakan untuk menghasilkan SHA-256 hash. Perbedaan sekecil apa pun pada format, spasi, baris baru, maupun nilai dapat menyebabkan Signature tidak valid.
- Contoh di atas menggunakan Access Token dan Signature demo sehingga request tidak akan berhasil apabila dikirimkan secara langsung.
- Sebelum melakukan pengujian, ganti seluruh nilai demo dengan **Access Token**, **Client Secret**, dan **Merchant Client ID&#x20;**&#x79;ang sesuai dengan environment yang digunakan.
:::

Selain itu, Merchant juga dapat membandingkan hasil yang diperoleh dengan output dari command terminal berikut:

:::BlockQuote
BODY='\{"partnerServiceId":"","customerNo":"","virtualAccountNo":"","virtualAccountName":"Jhon Doe","trxId":"2022020100000000000001","totalAmount":\{"value":"10000.00","currency":"IDR"},"additionalInfo":\{"bankCd":"BMRI","goodsNm":"Jhon Doe","dbProcessUrl":"https\://dev-services.nicepay.co.id/IONPAY\_CLIENT/paymentResult.jsp"}}'

BODY\_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 | awk '\{print $NF}')

STRING\_TO\_SIGN="POST:/api/v1.0/transfer-va/create-va\:DEMO\_ACCESS\_TOKEN\_0123456789:$&#x7B;BODY\_HASH}:2024-12-31T10:11:40+07:00"

printf '%s' "$STRING\_TO\_SIGN" | openssl dgst -sha512 -hmac "DEMO\_CLIENT\_SECRET\_0123456789" -binary | openssl base64 -A
:::



## Kesalahan Umum pada Pembuatan Signature

| **Case**                                        | **Penyebab yang sering terjadi**                                               |
| ----------------------------------------------- | ------------------------------------------------------------------------------ |
| Signature ditolak meskipun kode terlihat benar. | Nilai `X-TIMESTAMP` pada `stringToSign` berbeda dengan yang dikirim di Header. |
| Signature ditolak hanya pada sebagian request.  | Body berubah setelah di-hash (spasi, urutan field, encoding).                  |
| Signature ditolak di semua reques&#x74;*.*      | Private Key tidak cocok dengan Public Key yang terdaftar di NICEPAY.           |
| Signature ditolak saat pindah environment.      | Memakai Client ID atau kunci dari satu environment di environment lain.        |
| Muncul karakter aneh pada Signature.            | Lupa melakukan *encode&#x20;*`Base64` atau ada baris baru yang ikut terbawa.   |

