DRgrtea

Medsos DRcjgrTeA

Media Sosial Duridwangurunatafkar

Alih Bahasa

English French German Spain Italian Dutch Russian Brazil Japanese Korean Arabic Chinese Simplified

DRMenuNavigasiBar

menunavngampar

drcnavbar

Beranda Tentangku Buku Tamu

Rabu, 12 Agustus 2026

APLIKASI WEB | S.ID.DURIDWANCIJAG.ONG

Aplikasi Web s.id.duridwancijag.ong 
===========================
Kawitan__sk_live_8pn0Mlp4lwO4sLta16K0fVHX2Q0WVQFy__Wekasan
===========================

===========================
Produk Link = IPS Tauhidul Afkar ||| https://s.id/ips-duridwangurunatafkar
===========================



Dokumentasi:
# s.id Developer Platform — API Keys, Webhooks & OAuth

> **Connect your apps with s.id.** This guide explains how to use the s.id public
> developer platform: authenticating with API keys, calling the REST API, receiving
> webhooks, and authorizing third-party apps with OAuth 2.0.
>
> Manage your credentials in the dashboard at **Dashboard → Developer**.
>
> **Interactive API reference (Swagger UI):** `https://dash.s.id/developer/api-docs`
> **OpenAPI spec:** `https://dash.s.id/openapi/sid-developer-api.json`

## Table of Contents

1. [Quick Start](#quick-start)
2. [API Keys](#api-keys)
3. [Public REST API](#public-rest-api)
4. [Webhooks](#webhooks)
5. [Verifying Webhook Signatures](#verifying-webhook-signatures)
6. [OAuth 2.0](#oauth-20)
7. [Rate Limits & Errors](#rate-limits--errors)
8. [Legacy API (v1)](#legacy-api-v1)

---

## Quick Start

1. Open **Dashboard → Developer → API Keys** and click **Create API Key**.
2. Pick the scopes your integration needs (e.g. `links:read`, `links:write`).
3. Copy the key — it starts with `sk_live_` and is shown **only once**.
4. Call the API with the key in the `Authorization` header:

```bash
curl https://api.s.id/v2/links \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

**Base URL:** `https://api.s.id/v2`

---

## API Keys

API keys authenticate server-to-server calls to the public REST API.

| Property | Detail |
|----------|--------|
| Format | `sk_live_` + 32 random base62 chars |
| Header | `Authorization: Bearer sk_live_...` |
| Storage | Hashed (SHA-256) at rest — s.id never stores the raw key |
| Visibility | Shown once on creation; revoke + recreate if lost |
| Scopes | Per-key; a request to an endpoint without the required scope returns `403` |

### Scopes

| Scope | Grants | Status |
|-------|--------|--------|
| `links:read` | List and read links | Available |
| `links:write` | Create and update links (create, edit, restore) | Available |
| `links:archive` | Archive links | Available |
| `links:analytics` | Read per-link and account-level click statistics | Available |
| `qr:read` | Read QR codes for links | Available |
| `qr:write` | Update QR code customization for links | Available |
| `user:read` | Read the authenticated user profile and account quota | Available |
| `microsites:read` | List and read microsites | Available |
| `microsites:write` | Create, update and manage components of microsites | Available |
| `microsites:delete` | Delete microsites and their components | Available |

### Managing keys

Keys are managed via your logged-in session (not with an API key):

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/v1/keys` | List your keys |
| `POST` | `/api/v1/keys` | Create a key (`{ "name", "scopes": [] }`) |
| `PATCH` | `/api/v1/keys/:id` | Rename / change scopes |
| `DELETE` | `/api/v1/keys/:id` | Revoke a key |

---

## Public REST API

All routes below accept `Authorization: Bearer sk_live_...` (an API key) **or** an OAuth 2.0 access
token, and require the listed scope.
**Rate limit:** 38 requests/minute per credential (per `sk_live_*` key or per OAuth token) by
default; OAuth apps also have a per-app ceiling. See [Rate Limits & Errors](#rate-limits--errors).

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/v2/links` | `links:read` | List links (`?page=&limit=&search=`) |
| `POST` | `/v2/links` | `links:write` | Create a short link |
| `POST` | `/v2/links/bulk` | `links:write` | Create up to 100 links in one request |
| `POST` | `/v2/links/available` | `links:read` | Check if a custom slug is free |
| `GET` | `/v2/links/:short` | `links:read` | Get one link by short code |
| `PUT` | `/v2/links/:short` | `links:write` | Update a link |
| `DELETE` | `/v2/links/:short` | `links:archive` | Archive a link |
| `POST` | `/v2/links/:short/unarchive` | `links:write` | Restore an archived link |
| `GET` | `/v2/links/:short/stats` | `links:analytics` | Per-link click statistics timeline |
| `GET` | `/v2/links/:short/stats/lifetime` | `links:analytics` | Per-link lifetime click count |
| `GET` | `/v2/stats` | `links:analytics` | Account-level click analytics (timeline + breakdowns) |
| `GET` | `/v2/links/:short/qr` | `qr:read` | QR code for a link |
| `PUT` | `/v2/links/:short/qr` | `qr:write` | Update QR customization (logo + color) for a link |
| `GET` | `/v2/qr` | `qr:read` | Account-level default QR code |
| `PUT` | `/v2/qr` | `qr:write` | Update the account-level default QR code |
| `GET` | `/v2/microsites` | `microsites:read` | List your microsites |
| `POST` | `/v2/microsites` | `microsites:write` | Create a microsite |
| `POST` | `/v2/microsites/available` | `microsites:read` | Check if a microsite slug is free |
| `GET` | `/v2/microsites/:slug` | `microsites:read` | Get one microsite by slug |
| `PUT` | `/v2/microsites/:slug` | `microsites:write` | Update a microsite (title, description, visibility) |
| `DELETE` | `/v2/microsites/:slug` | `microsites:delete` | Delete a microsite |
| `GET` | `/v2/microsites/:slug/components` | `microsites:read` | List a microsite's components |
| `POST` | `/v2/microsites/:slug/components` | `microsites:write` | Add a component to a microsite |
| `POST` | `/v2/microsites/:slug/components/order` | `microsites:write` | Reorder a microsite's components |
| `PUT` | `/v2/microsites/:slug/components/:componentId` | `microsites:write` | Update a microsite component |
| `DELETE` | `/v2/microsites/:slug/components/:componentId` | `microsites:delete` | Delete a microsite component |
| `GET` | `/v2/user` | `user:read` | Authenticated user profile |
| `GET` | `/v2/quota` | `user:read` | Account quota and usage |

### Check slug availability

```bash
curl -X POST https://api.s.id/v2/links/available \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"short": "myslug"}'
```

> **Note:** the request body field is `short`, not `slug`.

Response:

```json
{ "data": { "available": true } }
```

### Create a link

```bash
curl -X POST https://api.s.id/v2/links \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "long_url": "https://drcontoh.co.id/a-url-sangat-panjang",
    "title": "My Link",
    "custom_slug": "drlinkesdotid"
  }'
```

Response:

```json
{
  "data": {
    "id": 123,
    "short": "drlinkesdotid",
    "short_url": "https://s.id/drlinkesdotid",
    "long_url": "https://drcontoh.co.id/a-url-sangat-panjang",
    "microsite": false,
    "protected": false,
    "disposable": false,
    "adult": false
  },
  "message": "link_created"
}
```

### Update a link

`PUT /v2/links/:short` accepts any combination of these optional fields:

| Field | Type | Description |
|-------|------|-------------|
| `long_url` | string | New destination URL (max 2083 chars) |
| `title` | string | Display title (max 48 chars) |
| `password` | string | Set or clear a link password (max 255 chars) |
| `disposable` | bool | Mark as disposable (single-use) |
| `adult` | bool | Mark as adult content |
| `custom_slug` | string | New short code (max 48 chars) |
| `archive_at` | string | ISO 8601 datetime to auto-archive |
| `domain_alias` | string | Custom domain alias |

---

## Webhooks

Webhooks push real-time events to your server. Register an endpoint in
**Dashboard → Developer → Webhooks** (or via the API), choose the events you care
about, and s.id will `POST` a JSON payload to your URL when they happen.

### Events

| Event | Fires when | Status |
|-------|-----------|--------|
| `link.created` | A link is created (UI or API) | Available |
| `link.updated` | A link's destination/title/slug changes | Available |
| `link.archived` | A link is archived (deleted) | Available |
| `link.clicked` | A link is visited | Available |
| `microsite.published` | A microsite is created or made public (hidden → visible) | Available |
| `qr.scanned` | A link is visited from its QR code (`s=qr` marker detected) | Available |

### Delivery

- **Method:** `POST` with `Content-Type: application/json`
- **Retries:** up to 3 attempts per event with back-off (0 s, 5 s, 30 s)
- **Auto-disable:** after 5 consecutive failed *events*, the webhook is disabled
  (a single transient failure won't disable it)
- Re-enable by recreating the webhook once your endpoint is healthy

### Headers

| Header | Description |
|--------|-------------|
| `X-SID-Event` | The event name, e.g. `link.created` |
| `X-SID-Signature` | `sha256=<hmac-hex>` — see below |
| `X-SID-Delivery-ID` | Unique delivery identifier |
| `User-Agent` | `s.id-Webhooks/1.0` |

### Example payload

```json
{
  "event": "link.created",
  "link": {
    "id": 123,
    "short": "drlinkesdotid",
    "short_url": "https://s.id/drlinkesdotid",
    "long_url": "https://drcontoh.co.id/a-url-sangat-panjang",
    "title": "My Link",
    "created": "2026-06-22T10:00:00Z"
  },
  "timestamp": "2026-06-22T10:00:00Z"
}
```

### Testing & history

- **Test delivery:** the **Test** button (or `POST /api/v1/webhooks/:id/test`) sends a
  sample payload and shows the HTTP status your endpoint returned.
- **Delivery history:** the **Deliveries** drawer (or `GET /api/v1/webhooks/:id/deliveries`)
  lists recent attempts with status code, error and timestamp.

> **Note:** webhooks only fire for events that actually occur on your account after the
> webhook is registered. If you see *"no deliveries yet"*, create or update a link (for
> `link.created` / `link.updated`) or use **Test** to generate a delivery.

---

## Verifying Webhook Signatures

Every delivery is signed with HMAC-SHA256 of the **raw request body**, using your
webhook's signing secret (shown once on creation). Always verify before trusting a payload.

`X-SID-Signature: sha256=<hex>`

### Node.js

```js
import crypto from "node:crypto";

function verify(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader),
  );
}
```

### Go

```go
func verify(rawBody []byte, signatureHeader, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(rawBody)
    expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signatureHeader))
}
```

---

## OAuth 2.0

For apps acting **on behalf of other s.id users**, use the OAuth 2.0 authorization-code flow
with PKCE.

| Endpoint | Host | Description |
|----------|------|-------------|
| `GET /oauth/authorize` | `https://api.s.id` | Redirect the user's browser here; it 302s to the `dash.s.id` consent screen (user approves/denies your app + scopes) |
| `POST /oauth/token` | `https://api.s.id` | Exchange `code` for tokens; also `grant_type=refresh_token` |
| `POST /oauth/revoke` | `https://api.s.id` | Revoke an access or refresh token (RFC 7009) |
| `GET /oauth/userinfo` | `https://api.s.id` | Profile of the authorizing user (`Authorization: Bearer <access_token>`) |

> All OAuth 2.0 endpoints — including `/oauth/authorize` — are served by `api.s.id`, the same
> host as `/v2/*`. `GET /oauth/authorize` is the one your user's browser navigates to; it
> redirects (302) to the actual consent UI on the dashboard frontend at `dash.s.id`, preserving
> the query string, then the consent page calls back into `api.s.id` for the consent data it
> renders. You never need to hard-code `dash.s.id` yourself — redirect to `api.s.id` and the
> redirect chain takes care of the rest.

### PKCE (Proof Key for Code Exchange)

- **Public clients** (no client secret) MUST send `code_challenge` + `code_challenge_method=S256`
  to `/oauth/authorize` — omitting it returns `code_challenge_required`.
- **Confidential clients** (issued a `client_secret`) may use PKCE too; if `code_challenge` is
  present, `code_challenge_method` must still be `S256` (`plain` is rejected with
  `unsupported_code_challenge_method`).
- Derive `code_challenge = BASE64URL(SHA256(code_verifier))` from a random `code_verifier`, and
  send the original `code_verifier` (not the challenge) when exchanging the code at `/oauth/token`.
- An authorization `code` is **single-use**: it's consumed as soon as `/oauth/token` is called,
  even if that call fails (e.g. wrong `code_verifier`). Request a fresh code via `/oauth/authorize`
  to retry.

Flow:

1. Redirect the user to `https://api.s.id/oauth/authorize?client_id=...&redirect_uri=...&scope=...&response_type=code&code_challenge=...&code_challenge_method=S256`.
2. After consent, s.id redirects back to your `redirect_uri` with `?code=...&state=...`.
3. Exchange the code at `POST https://api.s.id/oauth/token` for an `access_token` + `refresh_token`
   — confidential clients also send `client_secret`; send `code_verifier` if PKCE was used.
4. Call `GET https://api.s.id/oauth/userinfo` with the access token to read the authorizing
   user's profile. Refresh with `grant_type=refresh_token` when it expires (this rotates the
   refresh token — the old one is invalidated immediately).

> Access and refresh tokens are SHA-256 hashed at rest and have a fixed expiry (access token:
> 1 hour, refresh token: 30 days) — the raw token is returned to your app only at issue time.

> Access tokens are accepted on every `/v2/*` endpoint described above, in addition to
> `/oauth/userinfo` — send `Authorization: Bearer <access_token>` exactly as you would an
> `sk_live_*` API key. `/v2/*` enforces the same per-endpoint scopes either way, but OAuth
> grants stay granular: a token authorized for `microsites:write` will **not** implicitly gain
> `microsites:delete` the way a legacy API key does. `sk_live_*` keys remain fully supported for
> first-party server-to-server use; OAuth is for third-party integrations acting on behalf of a
> user. **Replace ≠ remove** — pick whichever fits your integration, both work on `/v2/*`.
>
> `/v2/*` and the OAuth authorization/token endpoints both live on `api.s.id` — a single host
> for every server-to-server call, whether authenticated with an `sk_live_*` key or an OAuth
> Bearer token.
>
> A `401` on `/v2/*` from an OAuth Bearer token carries a `WWW-Authenticate` header and a JSON
> body distinguishing three cases: `invalid_request` (missing/malformed header), `invalid_token`
> (unknown or revoked token — re-run the authorization flow), and `token_expired` (use the
> refresh token instead of re-authorizing).
>
> **Discovery:** `GET https://api.s.id/.well-known/oauth-authorization-server` (RFC 8414)
> advertises all endpoint URLs, `scopes_supported`, and `code_challenge_methods_supported` —
> standards-compliant OAuth libraries can configure themselves from it instead of hard-coding
> our URLs.
>
> **Token introspection:** `POST https://api.s.id/oauth/introspect` (RFC 7662) — a
> client-credential-protected endpoint for resource servers or debugging tools to check whether
> a token is alive and which scopes it carries. Body: `{"token": "...", "client_id": "...",
> "client_secret": "..."}`. Always returns `200` with `{"active": false}` for any unknown,
> expired, or revoked token (never an error), and `{"active": true, "scope": "...",
> "client_id": "...", "sub": "...", "exp": ..., "token_type": "Bearer"}` for a live one.

### OAuth errors

| Code | Meaning |
|------|---------|
| `invalid_oauth_request` | Missing `client_id`/`redirect_uri`, or `response_type` isn't `code` |
| `oauth_client_not_found` / `invalid_client` | Unknown `client_id`, or bad `client_secret` |
| `invalid_redirect_uri` | `redirect_uri` doesn't exactly match one registered for the client |
| `code_challenge_required` | Public client omitted PKCE `code_challenge` |
| `unsupported_code_challenge_method` | `code_challenge_method` other than `S256` |
| `invalid_grant` | Code/refresh token invalid, expired, already used, or `code_verifier` mismatch |
| `code_expired` | Authorization code expired (10 minute lifetime) |
| `unsupported_grant_type` | `grant_type` isn't `authorization_code` or `refresh_token` |

---

## Rate Limits & Errors

- **Rate limit:** 38 requests/minute per credential — per `sk_live_*` key or per individual OAuth
  access token. Exceeding it returns `429` with `{"error":"rate_limit_exceeded"}`.
- **Per-app rate limit (OAuth only):** a second, more generous ceiling (500 requests/minute) applies
  across all of an OAuth app's tokens combined, so one runaway integration with many authorized
  users can't exhaust shared capacity even though no single user's token trips the per-credential
  limit above. Exceeding it returns `429` with `{"error":"client_rate_limit_exceeded"}`.
- **Missing scope:** `403` with `{"error":"insufficient_scope","required":"<scope>"}`.
- **Invalid/expired key or token:** `401`. For OAuth Bearer tokens this distinguishes
  `invalid_request`, `invalid_token`, and `token_expired` — see the OAuth section above.
- **Validation errors:** `422` with a descriptive message key.

Standard success envelope:

```json
{ "data": { /* ... */ }, "message": "..." }
```

---

## Legacy API (v1)

> **Deprecated — existing integrations continue to work, but new integrations should use
> the v2 API above.**

The v1 API uses a different credential system: a static **auth ID** + **auth key** pair
tied to your user account (not scoped). These credentials are issued on a per-user basis
and cannot be scoped to individual capabilities.

### Credentials

| Header | Value |
|--------|-------|
| `X-Auth-Id` | Your numeric user ID |
| `X-Auth-Key` | Your account API key |

Creating or regenerating v1 keys is **no longer available** from the dashboard. Existing
grandfathered keys remain functional. Migrate to `sk_live_*` v2 keys at your earliest
convenience.

### v1 endpoints (read-only reference)

v1 is served at `https://api.s.id/v1/` and mirrors the v2 capability set. Use the v2
paths and auth above for all new integrations.

---

> **Last updated: June 2026** — covers v2 of the s.id developer API.
> Source of truth: `docs/developer-platform-guide.md` in the s.id repo.
> Guide + OpenAPI spec propagated to both repos via `scripts/sync-developer-docs.sh`.

Tidak ada komentar:

Posting Komentar

Posting Populer

Duridwan TeA Google Arsip

DRLabel

.NETdr 'Urwah ۝۞ دعاء الأوراد ۞۝ 1drive 2019 3Dwarehouse Abaib Academia AdminisGuru Adzan AKGTK Akrab 9497 AkselelatorDRc Aksioma Alfa Aljamal amrik Anakku Android Apache API Aplikasi Aplikasi Online Aplikasiku aqidah aqo'id Arsiper Arudl ASPnet Atribusi Attaqwa Audacity Audio Aurod AutoCAD ba'da sholat Ba'diyah Babad Bahasa Indonesia Balaghoh Baleomol bangpol Banner basund Belajar.id Biantara bilibiliTV bing.com Biografi Bisikan Bisnis Blog blogger blogku Bluestack BMTT Bola Dunia Boxmode BUKU C++ Caknun Canva Capcut CData Cerita Chanel Cijagong cmd Copast Coreldraw;Koreldrow cortang CPANEL cv Daftar Isi Daftar Tamu Dailymotion Dakwah Daring db515TB Dek@t Dikdasmen Diktat Do''a Do'a Domainesia dongeng Download drafdrong DRappc DRctvone DRcVivaTV drDana drDropbox DRlink drMedsos drSamiraTeA DRsampeu drSoftaculous drSQL DRxampp DTD Duridwancijag duridwanMI Duridwanvhost E-Book Earth eDGe Edmodo Edwin eftepe ekstensi Emulated Epson eSDeKU Excel Facebook Fafa Belajar favicon FB FBwatch Fikih Film FKGN FKSS Flickr ftf ftp Gambar Gaweku GDexcel GDrive GDword Gem26 Gif Giphy Github Goguru GooForm googele GooTeA GooWork Gosiswawi GS v2 Gudang Gif GuMeng Guru Hotmail HP HPpc HPrint HUDHUD ATTWITERI humor HVR iframe IHTT IIS IKBAL ikonku Ilham Ilmu Waris Imam Mahdi Iman imrithi imtihan Inlislite ips Ips siswa irkhash Ishol Israel Jackie Chan JadwalHirup Jendelatea Jerosimut Jurumiah Kaamengan Kaldik karuhun Kasintu Kasyif Kemdak Kenangan Kepesantrenan KHMZ Khutbah Idul Adha Khutbah Jum'at Kitab Koneng KlaudiAwan KMS KodeBlok Koding Komentarku konsorsium Kristen KSM KSM_24 kulsub Kumer Kutab Kuning Lalogin Laporan Laporan25 link lirik sunda Literasi LKSATA Logo lokalhost Lokasi LTNU lynk Malaikat Mama Gelar manifes mapel Mapel Plus marawis materi ajar materi ips materi sunda Mediafire Menu Mulai Messenger meta Metode Belajar MGMP MTS Mi.co.id Microsoft Mikrosoft Word MikrosofTeA MKKS MKSS MKT Modul MongoDB MoU Movie MPLS MSN MTs. Muhawarot Mushaf Sunda Mvs Nabi nadhom nahwu Nashoih Nasihat Pernikahan Nasrudin Hoja Nasyid NewTabTvSearch Ngablog ngaDOS Ngaji Pontren Nganet Ngaos ngaweb Ngimel Ngobrol Solat ngobrolgurutea ngoding Ngoleksi Nikah Nitro Nonton Nubuwwah NUID NUPTKku Nyekrip Nyitus OderPejKu Office office 2010 Office.co.id Offidocs ome Ome.TV omeaeun Onedrive Onlen Opis OpisTeA Oracle OSIS Outlook Pakakas Pamilarian Panulung PaperDropboxTeA PAS PAS S1 PAT PBNU pdf Penahexa Penilaian Perangkat Guru Peringatan Nabi perpus Perpusdig PHBI photo phpDuridwan Phyton Piaciseun Pintarkem PKKM PKKS PKSS PohonKeluarga Ponpes Portabel Post WA PPDB PPKKS Prkt Ltk Program Files Proker Proposal Prosem Prota PTS PTS S1 publikteaqta Pupujian Quran Sunda Rapat RDM Removal renungan Resize RFC RidsyafTeA Risalah Risalah Sholat RKS Rohbiyah Romadlon Romadon Rumus Rumus;PHP; RumusHead s.idku Safari Sambangan Santif Sanusi Scribd segitiga Sekolah seren tampi Sertifikat sholat Shopee Shorof sifat_20 Silaturahmi Simdif SIMPATIKA sinopsis sipd sisitv siswa sitegog Skenario Belajar Sketchup SketsaupTeA Slayid SMA Soal Soanten Software SoraTeuPerluNinggal StoryTelling STS Suara Sukapura sumputkeun sunda syare'at Ta'lim tabir mimpi Tadabbur tadarrus TafkarMart Tahajud Tahlil Tasbeh Taskbar Tauhid Tawasul Tema Blog tenor.com Terjemah Tiliktiktok TimTeA tips n trick Trik Tsaqifah tulisan TV Nasional Twitter Usaha Vektor Video Video Player Video;Edit Video;Rara VideoPost vidio w3s WA - AYT wahyu Wali Walimahan Wallpaper wayang WeA Windows Wirid Witir word Wordpress WordTeA WorldBank WP WPS WS XLS DRcjgTeA Yahoo yandexck Yapista link YT Ytduit ytDuridwanSunda YTstudio Yutub ZIP Zoom سلاح الدعوة

Tampil Ful Skrin

Tampilan penuh layar

Klik tombol "Penuh" untuk mode ful skrin. Tutup dengan cara klik tuts "Esc" di kibot, atau dengan mengklik tombol "Normal" saja.

Penuh Normal

Materi artikel

×
Judul