Sign with Singpass
Singpass Developer DocsAsk a Question
  • START HERE
    • Overview of Sign
    • How do our Digital Signatures work?
    • Frequently Asked Questions
  • FOR USERS
    • How to sign
    • Verifying Sign with Singpass Signatures
      • Loading Singpass Root Signing Certificate
  • FOR RELYING PARTIES
    • Use Cases
    • Getting Started
      • How to Onboard our API
      • Digital Signing Partners
        • Docusign
        • Tungsten Automation
        • OneSpan
        • Tessaract Technologies Pte Ltd
        • Netrust Pte Ltd
        • Modus Consulting
        • Redoc.co by Real Estate Doc Pte Ltd.
        • CrimsonLogic
        • Zoho Sign
        • Securemetric Technology Pte. Ltd.
        • Rently Pte. Ltd.
    • API Documentation
      • Document Signing V3
        • Initiate Sign Request
        • Redirect From Sign with Singpass
        • Accept Success Signing Webhook
        • Get Signing Result
        • JWKS Specification
        • Sign Portal
      • Document Signing V1
      • Transaction Signing
        • Embedding Singpass JS
        • Init Transaction Signing
        • Exchange Transaction Signature
    • UX Guidelines
      • User Journey Illustration
    • Support
Powered by GitBook
On this page
  • Changelog
  • Introduction
  • Document Signing Flow Diagram
  • Staging and Production URLs
  • DSAP Server Certificate
  • General Error Response
  • Description of fields
  • Error Codes
  • Document Signing endpoints invoked by DSAP
  • Authenticating via Basic Authentication (Deprecated)
  • Authenticating via JSON Web Token
  • POST /doc-signing-sessions
  • POST /doc-signing-sessions/<sign-ref>/hash
  • GET /.well-known/keys.json
  • DSAP Notification Webhook Endpoint
  • Usage
  • Specifications
  • IP Address Whitelisting
  • Request and Response Structure
  • Retry Settings
  • Error Response
  • Valid Error Codes
  • Other DSAP Requirements
  • Document Hash Specifications
  • Document Hash Signature Specifications
  • UI/UX Specifications
  • QR Code deeplinking specifications
  • Frequently Asked Questions (FAQs)

Was this helpful?

  1. FOR RELYING PARTIES
  2. API Documentation

Document Signing V1

Last Updated: 2 June 2025

PreviousSign PortalNextTransaction Signing

Last updated 7 days ago

Was this helpful?

We are no longer accepting requests to onboard Sign V1. Please refer to the instead.

Changelog

Date
Changes

30 Sep 2024

  • Deprecation of Basic Authentication

11 Nov 2024

Added IP addresses for whitelisting

5 Mar 2025

27 May 2025

2 June 2025

Introduction

The guide provide a clear illustration of the web-based application programming interfaces (API) for the use of Document Signing Application Providers (DSAP). Described here are the necessary APIs that DSAPs must invoke to facilitate a document signing process for a Singpass user.

Document Signing Flow Diagram

An overview of the document signing flow and the interactions between DSAP, Singpass and other dependencies.

Staging and Production URLs

Disclaimer: The domains used in the sample requests in the API specs below may not be accurate for your environment. Please choose the correct one from the table below that suits your testing needs.

Environment
Domain
Access Mechanism

Staging

  • SSL

  • Basic Authentication (Deprecated)

Production

  • SSL

  • Basic Authentication (Deprecated)

You must not do "cert pinning" or create any form of dependency to the leaf TLS certificates of the above domains. Singpass reserves the right to rotate its TLS leaf certificate without prior notice to partners.

mTLS is no longer required. We will ignore all incoming mTLS client authentication.

JWKS URLs

Environment
Domain
Access Mechanism

Staging

SSL

Production

SSL

Please note that there may be more than one key appearing in the JWKS, and DSAPs must use the kid value to identify the right key.

DSAP Server Certificate

Additionally, server certificates presented must minimally conform to the following requirements:

Requirement
RSA Certs
ECC Certs

Required Public Key dimensions

>= 2048 bits

>= 3072 bits (recommended)

>= 256-bit based on curves P-256, P-384 or P-521 (NIST curves, aka secp256r1, secp384r1, secp521r1 respectively)

X.509 v3 extension KeyUsage

digitalSignature, keyEncipherment

digitalSignature

X509 v3 extension ExtendedKeyUsage

serverAuth

serverAuth

General Error Response

DSS APIs are RESTful in design and communicate classes of errors based on the Http Status code. The status code should be used to determine if the error is caused by consumer or provider. Consumers should log the HTTP status code along with the id and/or trace_id of the error.

HTTP Status Code
Description

4XX

Errors caused by API consumer. You can expect codes such as 400, 401, 403, 404 etc if incorrect requests are made to APIs.

Example: 400: Invalid/missing request arguments

5XX

Errors caused by DSS or its dependencies. You can expect codes such as 500, 502, 503 etc if there is an issue on DSS or its dependencies.

Example: 500: Internal Server Error due to some kind of programming error.

Example: Invalid Request Parameters

HTTP/1.1 400 Bad Request
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Cache-Control: no-cache, no-store, must-revalidate
Transfer-Encoding: chunked
Content-Type: application/json
Date: Tue, 24 Sep 2024 02:30:42 GMT
Content-Length: 190

{
  "id" : "bcba4bc3-534e-4891-bfa2-e872b4502d80",
  "error" : "CLIENT_SIDE_ERROR",
  "error_description" : "This is an invalid request.",
  "trace_id" : "66f22452fb051066bf30f8002a3c5e4a"
}

Example: Server Error

HTTP/1.1 500 Internal Server Error
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Cache-Control: no-cache, no-store, must-revalidate
Transfer-Encoding: chunked
Content-Type: application/json
Date: Tue, 24 Sep 2024 02:30:42 GMT
Content-Length: 192

{
  "id" : "bcba4bc3-534e-4891-bfa2-e872b4502d80",
  "error" : "SERVER_SIDE_ERROR",
  "error_description" : "An unexpected error occurred.",
  "trace_id" : "66f22452d4ed47e5b4fbb870813ab8eb"
}

Description of fields

Path
Type
Description

id

String

The unique identifier for this error/request. Please log this identifier for support and debugging purposes.

trace_id

String

(Optional) An auxiliary id for request correlation across services. Please also log this identifier for operational support and debugging purposes.

error

String

Error code representing broad class of error. See Error Codes for the list of possible error codes that can be returned and what they represent.

error_description

String

Returns human readable general information about the reason for the error. Note that due to security reasons; detailed information is unlikely to be available in this message.

Error Codes

Error Code
Description

CLIENT_SIDE_ERROR

Generic error code for an invalid request.

SERVER_SIDE_ERROR

Generic error code for an error that occurred in Singpass.

UNAUTHORIZED

Authorization header value is invalid.

MISSING_AUTHORIZATION

Authorization header was required but not found.

ARGUMENTS_NOT_VALID

Some request parameters are invalid.

SIGN_REF_NOT_FOUND

Requested sign ref is invalid or has already expired.

MULTIPLE_ASSERTION_HEADER

Multiple DSS assertion headers.

ASSERTION_NOT_VALID

DSS assertion header is invalid.

JWKS_URL_NOT_FOUND

DSAP JWKS URL is not found.

CLIENT_JWKS_ERROR

Unable to fetch DSAP JWKS or DSAP JWKS is invalid.

Document Signing endpoints invoked by DSAP

The API in this sections are endpoints invoked by DSAPs at various part of the DSS flow.

  • /doc-signing-sessions

  • /doc-signing-sessions/<sign_ref>/hash

  • /.well-known/keys.json

Authenticating via Basic Authentication (Deprecated)

Authorization: Basic <client_id>:<client_secret>

Authenticating via JSON Web Token

DSAPs are to use JSON Web Token (JWT) assertion for authentication when calling the DSS APIs.

X-Dss-Assertion: <jwt_assertion>

Structure of JWT

Sample JWT

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJwLXRlc3QtMDEifQ.eyJpc3MiOiJtb2NrQ2xpZW50SWQiLCJzdWIiOiJtb2NrQ2xpZW50SWQiLCJhdWQiOiJodHRwczovL3N0YWdpbmcuc2lnbi5zaW5ncGFzcy5nb3Yuc2ciLCJpYXQiOjE3Mjc2NjUwMzcsImV4cCI6MTcyNzY2NTYzNywianRpIjoiN2Q2NDdmNTMtZDEzOC00YjUxLWIxZDgtZGM2OWQ1NmNhNDAxIn0.iF9WH09CW1zhOhaSH37Faaw6kw7dbUMx2yuIAW9tD7p50ixUWIBTswvwxkutIPFY4zGFxcjrV4USwBfxpe28RA

Decoded JWT Header

{
  "alg": "ES256",
  "typ": "JWT",
  "kid": "rp-test-01"
}
Parameter
Type

alg

String

Algorithm used in the JWT. Acceptable values are: ES256, ES384, ES512

typ

String

Acceptable value: JWT

kid

String

The Key ID used for the JWT. This value must correspond to a key in the DSAP JWKS endpoint.

Decoded JWT Body

{
  "iss": "mockClientId",
  "sub": "mockClientId",
  "aud": "https://staging.sign.singpass.gov.sg",
  "iat": 1727665037,
  "exp": 1727665637,
  "jti": "7d647f53-d138-4b51-b1d8-dc69d56ca401"
}
Parameter
Type
Description

iss

String

Use the ClientID provided by Singpass

sub

String

Use the ClientID provided by Singpass

aud

String

The DSS domain that will be accepting the JWT.

iat

Number

A Unix timestamp in seconds indicating the date and time when the JWT was issued.

exp

Number

A Unix timestamp in seconds indicating the date and time when the JWT will expire. Max expiry allowed is600 seconds from iat

jti

String

A random string that must be regenerated for each JWT to prevent replay attacks. Singpass will cache and reject all duplicate jti that is sent within a preset period. As such, DSAPs are advised to use a UUID-v4 value when populating this value.

DSAP JWKS Endpoint

Singpass will attempt to retrieve the public key from the DSAP JWKS endpoint in order to verify the JWT. This endpoint is provided during onboarding and is tied to the DSAP Client ID.

Singpass will only accept JWT signed by EC key. DSAP JWKS should have at least 1 EC key.

Sample JWKS Endpoint

{
  "keys": [
    {
      "kty": "EC",
      "x": "FuIv2xuY0coivK-MRg01T3_JHUMEtFHdpjj8AuxCPLA",
      "y": "N6pMWRTjPzsBdUTyLrhX7tftfx4IWxvL3z1s9PoxQlE",
      "crv": "P-256",
      "use": "sig",
      "kid": "sign-prod-01"
    }
  ]
}
Parameter
Type
Description

kty

String

Key Type Acceptable value: EC

x

String

X-Coordinate This is the X-coordinate of the elliptic curve point, which is a component of the public key. It is base64url-encoded.

y

String

Y-Coordinate This is the Y-coordinate of the elliptic curve point, which is a component of the public key. It is base64url-encoded.

crv

Number

Curve Name

use

Number

Public Key Use. Acceptable value: sig

kid

String

Key ID. Singpass will search for the kid that was specified in the JWT for verification.

alg

String

[Optional] Algorithm

DSAPs are to put the JWT in the request header with the key X-Dss-Assertion when calling all DSS APIs.

For existing DSAP that are currently using Basic Authentication, DSAPs can continue to use the Authorization header when calling DSS APIs. DSS APIs will first detect if X-Dss-Assertion exists in the header before falling back to Authorization. Existing DSAPs are advised to start preparing for the change to JWT early.

POST /doc-signing-sessions

DSAPs can call this endpoint to start a document signing session. On success, a unique signing reference value - sign_ref - is included in the response object. The sign_ref is the primary identifier of a signing session used in all exchanges between Singpass and DSAP.

DSAPs have to specify a client notification token when initialising a session. Singpass will specify this token in an Authorization header for subsequent calls to the DSAP notification webhook endpoints.

Please note that Singpass will not notify DSAPs when the signing session expires. It is recommended to make use of the aforementioned expires_at response field to coordinate the session expiry between Singpass and DSAPs.

Request and Response Structure

Sample Curl Request (Deprecated)

$ curl 'https://staging.sign.singpass.gov.sg/api/v1/doc-signing-sessions' -i -u 'client_id:client_secret' -X POST \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -d '{"tenant_id":"some_tenant_id","client_notification_token":"client_notification_token"}' \
    --cert client.crt --key client.key

Sample Curl Request (New)

$ curl 'https://staging.sign.singpass.gov.sg/api/v1/doc-signing-sessions' -i -X POST \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -H 'X-Dss-Assertion: <jwt-assertion>' \
    -d '{"tenant_id":"some_tenant_id","client_notification_token":"client_notification_token"}' \
    --cert client.crt --key client.key

Sample HTTP Request (Deprecated)

POST /doc-signing-sessions HTTP/1.1
Accept: application/json
Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=
Content-Type: application/json
Host: staging.sign.singpass.gov.sg
Content-Length: 86

{"tenant_id":"some_tenant_id","client_notification_token":"client_notification_token"}

Sample HTTP Request (New)

POST /doc-signing-sessions HTTP/1.1
Accept: application/json
X-Dss-Assertion: <jwt-assertion>
Content-Type: application/json
Host: staging.sign.singpass.gov.sg
Content-Length: 86

{"tenant_id":"some_tenant_id","client_notification_token":"client_notification_token"}

Sample Response

HTTP/1.1 200 OK
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Cache-Control: no-cache, no-store, must-revalidate
Transfer-Encoding: chunked
Content-Type: application/json
Date: Tue, 24 Sep 2024 02:30:17 GMT
Content-Length: 181

{"sign_ref":"4b1b5241-9594-4e98-b9e3-7f53b73e3fcc","expires_at":1727145019,"qr_code":{"payload":"https://app.singpass.gov.sg/docsign?sign_ref=4b1b5241-9594-4e98-b9e3-7f53b73e3fcc"}}// Some code

Request Body

Name
Type
Description

client_notification_token

String

A token provided by the DSAP to be used by Singpass when invoking the DSAP’s webhook endpoint.

Allowed Characters: Alphanumeric, underscore ( _ ), dash ( - ), and whitespace

Max length: 255 characters

tenant_id

String

The identifier of the tenant of the DSAP client using the doc signing service.

Allowed Characters: Alphanumeric, underscore ( _ ), dash ( - ), and whitespace

Max length: 255 characters

The value of the tenant_id is not the signer's identity. Rather, it is an unique identifier for the DSAP's corporate customers that we can refer to in case of any anomaly detected. If you are not reselling your service to a third party, you can reuse the DSAP name provided during onboarding as the tenant_id.

For example: If ABC Bank goes through DSAP to reach DSS, then tenant_id must be a unique identifier of ABC Bank. However, if ABC Bank is directly integrated with DSS, then tenant_id can be just ABC Bank.

Request Headers

Name
Description

Authorization

(Deprecated)

The DSAP’s client id and client secret in http basic authentication scheme format.

Not required if DSAP is using JWT to authenticate

X-Dss-Assertion

(New)

JWT issued by the DSAP for authentication.

Request Headers

Name
Description

Authorization

(Deprecated)

The DSAP’s client id and client secret in http basic authentication scheme format.

Not required if DSAP is using JWT to authenticate.

X-Dss-Assertion

(New)

JWT issued by the DSAP for authentication.

Response Body

Parameter Description
Type

sign_ref

String

The primary identifier of a signing session used in all exchanges between Singpass and DSAP.

qr_code.payload

String

The QR payload containing the sign ref in a format understood by SingPass Mobile (SPM). DSAPs are expected to encode and display this as a QR code for SPM users to scan. Refer to the UX Guide provided in the developer package for the QR code display specifications.

expires_at

Number

A Unix timestamp in seconds indicating the date and time when the sign_ref will expire.

Please note that sign_ref should not be treated as a UUID-v4, and the length of the sign_ref may vary from time to time.

The host of the URL in qr_code.payload in staging environment will change to stg-app.singpass.gov.sg after 18 Mar 2025.

Error Responses

POST /doc-signing-sessions/<sign-ref>/hash

DSAPs must use this endpoint to send the document hash, document name, and challenge code to Singpass. Singpass will then forward the document information and challenge code to the user for verification and signing.

Request and Response Structure

Sample Curl Request (Deprecated)

$ curl 'https://staging.sign.singpass.gov.sg/api/v1/doc-signing-sessions/c6258905-c196-4465-9182-4d95e0163e96/hash' -i -u 'client_id:client_secret' -X POST \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -d '{
  "challenge_fqdn" : "signing-partner.gov.sg",
  "doc_name" : "signable-document.pdf",
  "nonce" : "bxUoQ4XiThs0oR19arXcaHpj+lm+i0BPta4YeTXkLXX=",
  "app_launch_url" : "com.example.dsap://home",
  "doc_hash" : "6AC7637DA92C76385F95A92C7617E591A8F6DF8F74F37EF8DB7E25E648E1DB7E",
  "challenge_code" : "1567"
}' \
    --cert client.crt --key client.key

Sample Curl Request (New)

$ curl 'https://staging.sign.singpass.gov.sg/api/v1/doc-signing-sessions/c6258905-c196-4465-9182-4d95e0163e96/hash' -i -X POST \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -H 'X-Dss-Assertion: <jwt-assertion>' \
    -d '{
  "challenge_fqdn" : "signing-partner.gov.sg",
  "doc_name" : "signable-document.pdf",
  "nonce" : "bxUoQ4XiThs0oR19arXcaHpj+lm+i0BPta4YeTXkLXX=",
  "app_launch_url" : "com.example.dsap://home",
  "doc_hash" : "6AC7637DA92C76385F95A92C7617E591A8F6DF8F74F37EF8DB7E25E648E1DB7E",
  "challenge_code" : "1567"
}' \
    --cert client.crt --key client.key

Sample HTTP Request (Deprecated)

POST /doc-signing-sessions/c6258905-c196-4465-9182-4d95e0163e96/hash HTTP/1.1
Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=
Accept: application/json
Content-Type: application/json
Host: staging.sign.singpass.gov.sg
Content-Length: 309

{
  "challenge_fqdn" : "signing-partner.gov.sg",
  "doc_name" : "signable-document.pdf",
  "nonce" : "bxUoQ4XiThs0oR19arXcaHpj+lm+i0BPta4YeTXkLXX=",
  "app_launch_url" : "com.example.dsap://home",
  "doc_hash" : "6AC7637DA92C76385F95A92C7617E591A8F6DF8F74F37EF8DB7E25E648E1DB7E",
  "challenge_code" : "1567"
}

Sample HTTP Request (New)

POST /doc-signing-sessions/c6258905-c196-4465-9182-4d95e0163e96/hash HTTP/1.1
Accept: application/json
X-Dss-Assertion: <jwt-assertion>
Content-Type: application/json
Host: staging.sign.singpass.gov.sg
Content-Length: 309

{
  "challenge_fqdn" : "signing-partner.gov.sg",
  "doc_name" : "signable-document.pdf",
  "nonce" : "bxUoQ4XiThs0oR19arXcaHpj+lm+i0BPta4YeTXkLXX=",
  "app_launch_url" : "com.example.dsap://home",
  "doc_hash" : "6AC7637DA92C76385F95A92C7617E591A8F6DF8F74F37EF8DB7E25E648E1DB7E",
  "challenge_code" : "1567"
}

Sample HTTP Response

HTTP/1.1 200 OK
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Date: Tue, 24 Sep 2024 02:30:20 GMT

Path Parameters

Parameter
Description

sign_ref

The primary identifier of a signing session used in all exchanges between Singpass and DSAP

Request Body

{
  "challenge_fqdn" : "signing-partner.gov.sg",
  "doc_name" : "signable-document.pdf",
  "nonce" : "bxUoQ4XiThs0oR19arXcaHpj+lm+i0BPta4YeTXkLXX=",
  "app_launch_url" : "com.example.dsap://home",
  "doc_hash" : "6AC7637DA92C76385F95A92C7617E591A8F6DF8F74F37EF8DB7E25E648E1DB7E",
  "challenge_code" : "1567"
}

Request Fields

Parameter
Type
Description

doc_name

String

The name of the document to be signed by the user. Do note that this value will be displayed to the user, so it is recommended to use a human-readable name.

Length must be between 1 and 255

doc_hash

String

Length must be 64

challenge_code

String

A set of characters used by the user to visually verify the signing session between the Singpass App and the DSAP website.

Length must be 4. Numerical values are recommended.

nonce

String

Singpass-generated random string sent to the DSAP's webhook endpoint during user certificate notification.

challenge_fqdn

String

The domain name of the webpage displaying the QR code. This will be displayed to the user on the Singpass app.

Length must be between 1-255

app_launch_url

String

(Optional) This adds the possibility for the user to be redirected back to the provided App Link after they successfully authorize themselves on the Singpass App. The value passed here should be the App Link registered with Apple’s App Store and/or Google’s Play Store.

Max length allowed is 255 characters.

Request Headers

Name
Description

Authorization

(Deprecated)

The DSAP’s client id and client secret in http basic authentication scheme format. Not required if DSAP is using JWT to authenticate

X-Dss-Assertion

(New)

JWT issued by the DSAP for authentication.

Response Body

There is no body in the response for successful API call.

Error Response

If Singpass fails to find the requested sign_ref (e.g. due to expiry), this API will return a HTTP 400 error, and an accompanying SIGN_REF_NOT_FOUNDerror code in the response body.

GET /.well-known/keys.json

Request and Response Structure

Sample Curl Request

$ curl 'https://static.staging.sign.singpass.gov.sg/.well-known/keys.json' -i -X GET

Sample HTTP Request

GET /.well-known/keys.json HTTP/1.1
Host: static.staging.sign.singpass.gov.sg

Sample HTTP Response

HTTP/1.1 200 OK
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Cache-Control: max-age=21600, must-revalidate, no-transform, public
Content-Type: application/json
Content-Length: 436
Date: Tue, 24 Sep 2024 02:30:00 GMT

{
  "keys" : [ {
    "kty" : "EC",
    "use" : "sig",
    "crv" : "P-256",
    "kid" : "ndi_dss_signer_02",
    "x" : "ObZ0BvgODnkQqMK5OjBWn5V6DCWlEhICwC7UuXxs-Vw",
    "y" : "c9CjVC779_rvOWMwbh4cE4Jx3bcfKe_20WVDtZYc_Ns"
  }, {
    "kty" : "EC",
    "use" : "sig",
    "crv" : "P-256",
    "kid" : "ndi_dss_signer",
    "x" : "dL8zGIrEMDfwlMxsd_uYqNbjq6PUHaswudG5lMJlcyI",
    "y" : "f2mU8Q2eE1pUsN37ktEHTf3n0u1u_2N7VRRus-3u4Z0"
  } ]
}

Request Body

There is no request body for this API call.

Response Body

{
  "keys" : [ {
    "kty" : "EC",
    "use" : "sig",
    "crv" : "P-256",
    "kid" : "ndi_dss_signer_02",
    "x" : "ObZ0BvgODnkQqMK5OjBWn5V6DCWlEhICwC7UuXxs-Vw",
    "y" : "c9CjVC779_rvOWMwbh4cE4Jx3bcfKe_20WVDtZYc_Ns"
  }, {
    "kty" : "EC",
    "use" : "sig",
    "crv" : "P-256",
    "kid" : "ndi_dss_signer",
    "x" : "dL8zGIrEMDfwlMxsd_uYqNbjq6PUHaswudG5lMJlcyI",
    "y" : "f2mU8Q2eE1pUsN37ktEHTf3n0u1u_2N7VRRus-3u4Z0"
  } ]
}

Caching and Key Rotation

Responses from this endpoint, or individual keys from inside the JWKS can and should be cached for at least 1 hour, and NOT retrieved for each JWT validation. Cache-Control headers on the response indicate a possible policy.

For varying reasons, keys used for signing can and will be rotated/changed with no defined schedule, and at the full discretion of Singpass. When a key rotation happens, the new key will be available from the JWKS endpoint and will have a different kid value. The new kid value will be reflected in all the new JWTs signed by Singpass. In such cases, cached copies of Singpass public keys must be refreshed by re-invoking the JWKS endpoint.

If the validation of the Singpass signature fails, re-fetch from the JWKS endpoint once for that validation.

Please read through the list of DON’Ts below:

  • Do not assume the position of a signing key among the list of the returned keys.

  • Do not validate Singpass signatures using a hardcoded public key OR kid. Always determine the correct key (for signature verification) by inspecting the kid from the JWS header, and use it to retrieve the public key from our JWKS endpoint.

  • Do not cache only 1 key. Caching should be done for the entire JWKS.

DSAP Notification Webhook Endpoint

Usage

Singpass will inform DSAP of various events that happen during the document signing process. To facilitate this, DSAPs must implement and expose a webhook endpoint to accept information from Singpass.

The DSAP’s webhook is the main and only mechanism for Singpass to notify the DSAP of the events that happen in the signing flow. DSAPs cannot poll or query Singpass to get the state of the user’s doc signing session. See the Session expiry section for details on how session expiry should be handled.

Singpass will call the webhook endpoint to inform of the following events:

  1. User certificate notification - To send the user’s certificate (See Step 6 of flow diagram).

  2. Document hash signature notification - To send the user’s document hash signature (See Step 14 of flow diagram).

  3. Webhook error notification - To inform DSAP of any errors encountered during the webhook calls above.

Please note that for all calls to the webhook endpoint, DSAPs are expected to respond HTTP 200 to the webhook calls immediately, before any significant processing is performed on the request. This is to keep low latencies on the user-facing APIs that are dependent on the webhook calls and give a better overall experience to Singpass users.

Specifications

  • The webhook must accept the POST HTTP method.

  • Singpass will perform automated retries of webhook requests if it encounters timeouts and on certain errors. See the webhook Retry Settings for more details.

  • It is sufficient for DSAPs to respond with an HTTP status code without any response body for this endpoint.

IP Address Whitelisting

Singpass will call your webhook endpoints from these IP addresses, which you may choose to whitelist.

Staging
Production

54.169.20.186

18.143.229.39

54.179.76.90

3.0.39.45

Request and Response Structure

Sample Curl Request

$ curl 'https://<dsap_domain_url>/dsap/webhook' -i -X POST \
    -H 'Authorization: Bearer <client_notification_token>' \
    -H 'Content-Type: application/json' \
    -d '{"token":"eyJraWQiOiJuZGlfZHNzX3NpZ25lciIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzaWduX3JlZiI6IjU2MTYzZTg5LWEyMzItNDUwMi1hNDRmLWUyMjI1MTJiYTFhZCIsInJlcXVlc3RfdHlwZSI6InVzZXJfY2VydCIsImV4cCI6MTcyNzE0NTE1MiwidXNlcl9jZXJ0IjoiTUlJQnJUQ0NBVEtnQXdJQkFnSUNBK2N3Q2dZSUtvWkl6ajBFQXdNd05URUxNQWtHQTFVRUJoTUNVMGN4RERBS0JnTlZCQW9NQTA1RVNURVlNQllHQTFVRUF3d1BkR1Z6ZEVCdVpHa3VaMjkyTG5Obk1CNFhEVEl3TURZd016QTNNalF5TjFvWERUSXdNRFl3TXpBM01qWXdOMW93VERFdE1Dc0dBMVVFQlJNa09HRmtPREExWW1VdE56Z3pOQzAwWWpZNExXRmxZek10Tm1NNE5UUTNObVpsWWpFeE1Sc3dHUVlEVlFRRERCSlRNREF3TURBd01Ea2dTbTlvYmlCRWIyVXdkakFRQmdjcWhrak9QUUlCQmdVcmdRUUFJZ05pQUFSb2FRWUVTQWpaUzBISnJwY1g1bWpRZlFzT0RaQ0s1WW1ybFdJejFyaXp3dzRBWEQ5bzRkdFJVZHBNOStGQWtlM2NreFlpWmM5SzJoYXZZdVRLLy9kM09KRzlFVHlyZ0VsVXRoV1c2R2FCZEZzV1pnRHMvenMzRkhyMFJvTThYLzB3Q2dZSUtvWkl6ajBFQXdNRGFRQXdaZ0l4QUw5WUl1M3hZMnY5YndiL2NoUWdPN0p6YnJxOGd0aTJOVmFoc0Q3Sk5kOUErOFJKcmR5QlRGZlpSMDA0elYzNk9RSXhBTzVZVHFYUWdydys1UFpXWjZSYWV3VkRKbjdEeXdYUUpiZXk3WnJ5MjdlZDdoeHNZYVQ5QlBBNElvNll5MmhHS1E9PSIsImlhdCI6MTcyNzE0NTAzMiwibm9uY2UiOiI5NjBiYzY5Yy1lY2M5LTRlOWEtODY4Yy04OTkyNTgwYjUyNTcifQ.ERUp7x8yEYZkdJEDU3z_0IZNYb0MdKknaoYYZXjQ8X4Dh29qtAP39W4N3dGJu_vvhYbtSjXX-JgXEINsMj8rtkkULZWsRXN8GTPalFTFc6l00_Kx09SLiha6Lc-UevED"}'

Sample HTTP Request

POST /dsap/webhook HTTP/1.1
Authorization: Bearer <client_notification_token>
Content-Type: application/json
Host: <dsap_domain_url>:443
Content-Length: 1215

{"token":"eyJraWQiOiJuZGlfZHNzX3NpZ25lciIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzaWduX3JlZiI6IjU2MTYzZTg5LWEyMzItNDUwMi1hNDRmLWUyMjI1MTJiYTFhZCIsInJlcXVlc3RfdHlwZSI6InVzZXJfY2VydCIsImV4cCI6MTcyNzE0NTE1MiwidXNlcl9jZXJ0IjoiTUlJQnJUQ0NBVEtnQXdJQkFnSUNBK2N3Q2dZSUtvWkl6ajBFQXdNd05URUxNQWtHQTFVRUJoTUNVMGN4RERBS0JnTlZCQW9NQTA1RVNURVlNQllHQTFVRUF3d1BkR1Z6ZEVCdVpHa3VaMjkyTG5Obk1CNFhEVEl3TURZd016QTNNalF5TjFvWERUSXdNRFl3TXpBM01qWXdOMW93VERFdE1Dc0dBMVVFQlJNa09HRmtPREExWW1VdE56Z3pOQzAwWWpZNExXRmxZek10Tm1NNE5UUTNObVpsWWpFeE1Sc3dHUVlEVlFRRERCSlRNREF3TURBd01Ea2dTbTlvYmlCRWIyVXdkakFRQmdjcWhrak9QUUlCQmdVcmdRUUFJZ05pQUFSb2FRWUVTQWpaUzBISnJwY1g1bWpRZlFzT0RaQ0s1WW1ybFdJejFyaXp3dzRBWEQ5bzRkdFJVZHBNOStGQWtlM2NreFlpWmM5SzJoYXZZdVRLLy9kM09KRzlFVHlyZ0VsVXRoV1c2R2FCZEZzV1pnRHMvenMzRkhyMFJvTThYLzB3Q2dZSUtvWkl6ajBFQXdNRGFRQXdaZ0l4QUw5WUl1M3hZMnY5YndiL2NoUWdPN0p6YnJxOGd0aTJOVmFoc0Q3Sk5kOUErOFJKcmR5QlRGZlpSMDA0elYzNk9RSXhBTzVZVHFYUWdydys1UFpXWjZSYWV3VkRKbjdEeXdYUUpiZXk3WnJ5MjdlZDdoeHNZYVQ5QlBBNElvNll5MmhHS1E9PSIsImlhdCI6MTcyNzE0NTAzMiwibm9uY2UiOiI5NjBiYzY5Yy1lY2M5LTRlOWEtODY4Yy04OTkyNTgwYjUyNTcifQ.ERUp7x8yEYZkdJEDU3z_0IZNYb0MdKknaoYYZXjQ8X4Dh29qtAP39W4N3dGJu_vvhYbtSjXX-JgXEINsMj8rtkkULZWsRXN8GTPalFTFc6l00_Kx09SLiha6Lc-UevED"}

Sample HTTP Response

HTTP/1.1 200 OK
Date: Tue, 24 Sep 2024 02:30:32 GMT
Connection: close

Request Body

{"token":"eyJraWQiOiJuZGlfZHNzX3NpZ25lciIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzaWduX3JlZiI6IjU2MTYzZTg5LWEyMzItNDUwMi1hNDRmLWUyMjI1MTJiYTFhZCIsInJlcXVlc3RfdHlwZSI6InVzZXJfY2VydCIsImV4cCI6MTcyNzE0NTE1MiwidXNlcl9jZXJ0IjoiTUlJQnJUQ0NBVEtnQXdJQkFnSUNBK2N3Q2dZSUtvWkl6ajBFQXdNd05URUxNQWtHQTFVRUJoTUNVMGN4RERBS0JnTlZCQW9NQTA1RVNURVlNQllHQTFVRUF3d1BkR1Z6ZEVCdVpHa3VaMjkyTG5Obk1CNFhEVEl3TURZd016QTNNalF5TjFvWERUSXdNRFl3TXpBM01qWXdOMW93VERFdE1Dc0dBMVVFQlJNa09HRmtPREExWW1VdE56Z3pOQzAwWWpZNExXRmxZek10Tm1NNE5UUTNObVpsWWpFeE1Sc3dHUVlEVlFRRERCSlRNREF3TURBd01Ea2dTbTlvYmlCRWIyVXdkakFRQmdjcWhrak9QUUlCQmdVcmdRUUFJZ05pQUFSb2FRWUVTQWpaUzBISnJwY1g1bWpRZlFzT0RaQ0s1WW1ybFdJejFyaXp3dzRBWEQ5bzRkdFJVZHBNOStGQWtlM2NreFlpWmM5SzJoYXZZdVRLLy9kM09KRzlFVHlyZ0VsVXRoV1c2R2FCZEZzV1pnRHMvenMzRkhyMFJvTThYLzB3Q2dZSUtvWkl6ajBFQXdNRGFRQXdaZ0l4QUw5WUl1M3hZMnY5YndiL2NoUWdPN0p6YnJxOGd0aTJOVmFoc0Q3Sk5kOUErOFJKcmR5QlRGZlpSMDA0elYzNk9RSXhBTzVZVHFYUWdydys1UFpXWjZSYWV3VkRKbjdEeXdYUUpiZXk3WnJ5MjdlZDdoeHNZYVQ5QlBBNElvNll5MmhHS1E9PSIsImlhdCI6MTcyNzE0NTAzMiwibm9uY2UiOiI5NjBiYzY5Yy1lY2M5LTRlOWEtODY4Yy04OTkyNTgwYjUyNTcifQ.ERUp7x8yEYZkdJEDU3z_0IZNYb0MdKknaoYYZXjQ8X4Dh29qtAP39W4N3dGJu_vvhYbtSjXX-JgXEINsMj8rtkkULZWsRXN8GTPalFTFc6l00_Kx09SLiha6Lc-UevED"}

Request Fields

Name
Type
Description

token

String

The signed JWT containing standard and custom claims that describe a user or error event of a digital signing session.

Request Headers

Name
Description

Authorization

Bearer token authentication credentials. The token value is equal to the client_notification_token provided by the DSAP during session initialization.

Response Body

There is no body in the response for this API call.

Request token structure

As mentioned previously, the request body token field is a JWT signed by Singpass, which can be verified by DSAPs.

JWT Header (User Certificate)

{
  "kid" : "ndi_dss_signer",
  "typ" : "JWT",
  "alg" : "ES256"
}

JWT Claims (User Certificate)

{
  "sign_ref" : "56163e89-a232-4502-a44f-e222512ba1ad",
  "request_type" : "user_cert",
  "exp" : 1727145152,
  "user_cert" : "MIIBrTCCATKgAwIBAgICA+cwCgYIKoZIzj0EAwMwNTELMAkGA1UEBhMCU0cxDDAKBgNVBAoMA05ESTEYMBYGA1UEAwwPdGVzdEBuZGkuZ292LnNnMB4XDTIwMDYwMzA3MjQyN1oXDTIwMDYwMzA3MjYwN1owTDEtMCsGA1UEBRMkOGFkODA1YmUtNzgzNC00YjY4LWFlYzMtNmM4NTQ3NmZlYjExMRswGQYDVQQDDBJTMDAwMDAwMDkgSm9obiBEb2UwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARoaQYESAjZS0HJrpcX5mjQfQsODZCK5YmrlWIz1rizww4AXD9o4dtRUdpM9+FAke3ckxYiZc9K2havYuTK//d3OJG9ETyrgElUthWW6GaBdFsWZgDs/zs3FHr0RoM8X/0wCgYIKoZIzj0EAwMDaQAwZgIxAL9YIu3xY2v9bwb/chQgO7Jzbrq8gti2NVahsD7JNd9A+8RJrdyBTFfZR004zV36OQIxAO5YTqXQgrw+5PZWZ6RaewVDJn7DywXQJbey7Zry27ed7hxsYaT9BPA4Io6Yy2hGKQ==",
  "iat" : 1727145032,
  "nonce" : "960bc69c-ecc9-4e9a-868c-8992580b5257"
}

Description of Claims (User Certificate)

Parameter
Type
Description

sign_ref

String

The primary identifier of a signing session used in all exchanges between Singpass and DSAP.

user_cert

String

The user's digital signing certificate in base64-encoded DER format.

iat

Number

A Unix timestamp in seconds indicating the date and time when the JWT was issued.

exp

Number

A Unix timestamp in seconds indicating the date and time when the JWT will expire.

nonce

String

A randomly generated string used to associate this user certificate notification to a document hash callback . This nonce must be included in the subsequent document hash callback request from DSAP.

request_type

String

Value to indicate the type of the request, value is user_cert.

Description of Claims (Document Hash Signature)

Parameter
Type
Description

sign_ref

String

The primary identifier of a signing session used in all exchanges between Singpass and DSAP.

doc_hash

String

iat

Number

A Unix timestamp in seconds indicating the date and time when the JWT was issued.

exp

Number

A Unix timestamp in seconds indicating the date and time when the JWT will expire.

doc_hash_signature

String

request_type

String

Value to indicate the type of the request, value is signed_doc_hash.

Description of Claims (Error)

Parameter
Type
Description

sign_ref

String

The primary identifier of a signing session used in all exchanges between Singpass and DSAP.

error

String

Error code representing an error, e.g. CLIENT_NOTIFICATION_FAILED

iat

Number

A Unix timestamp in seconds indicating the date and time when the JWT was issued.

exp

Number

A Unix timestamp in seconds indicating the date and time when the JWT will expire.

error_description

String

Returns human readable general information about the reason for the error.

request_type

String

Value to indicate the type of the request, value is error.

ndi_request_id

String

A randomly generated ID that can be used to correlate requests between Singpass and DSAP. This ID is unique per user request.

Retry Settings

Singpass will retry on any connection errors, client timeout and the following http response codes returned from the DSAP webhook endpoint:

  • 502 - BAD_GATEWAY

  • 503 - SERVICE_UNAVAILABLE

  • 504 - GATEWAY_TIMEOUT

Singpass is using the following configuration for retry strategy:

Total timeout across all attempts: 5s
Per try timeout: 2s
Min back off: 500ms
Max attempts: 3

Error Response

The DSAP webhook API must follow RESTful conventions and communicate errors by returning a proper error response and with a corresponding HTTP status code, following the structure indicated below. All fields are mandatory.

Response Fields

Parameter
Type
Description

id

String

A randomly generated ID that can be used to correlate requests between Singpass and DSAP. This ID is unique per user request.

error

String

error_description

String

Returns human readable general information about the reason for the error.

Sample Error Response

{
  "id" : "1234",
  "error" : "SIGN_REF_NOT_FOUND",
  "error_description" : "The requested sign ref does not exist."
}

Valid Error Codes

Error
Expected Http Status

SIGN_REF_NOT_FOUND

400

To be returned if the sign ref in the request is unknown or expired.

INVALID_REQUEST

400

A catch all indicating an invalid request parameter from DSS. Eg. invalid client notification token, invalid user cert, invalid doc hash signature, etc.

SERVER_ERROR

5XX

A catch all for any other errors that occurred in the DSAP.

Other DSAP Requirements

DSAPs are expected to verify the validity of the user’s certificate status against National Certificate Authority (NCA).

Singpass only validates the expiry, signature and signer of the certificate against the NCA Root and Intemediary CAs.

  • DSAPs shall not send unknown OCSP requests (e.g. unknown OCSP certificate serial number or unknown CA Hash name).

  • Cryptographic algorithms: DSAP shall ensure that the default cryptographic algorithms used in its systems and during the Digital Signing Process are as follows:

    • Digital Signature Algorithms: ECDSA (key size with 256 bits or more);

    • ECC Curves: NIST P-256, P-384, P-521;

    • Hash Algorithms: SHA-2 (256/384/512).

Document Hash Specifications

The document hash should be SHA256 hashed and hex-encoded before sending to Singpass.

Document Hash Signature Specifications

The document hash is locally signed by the user’s digital identity, verified by Singpass and then sent to the DSAP.

The document hash is not re-hashed during signing.

UI/UX Specifications

DSAPs should follow the UX Guide provided in the developer package given during onboarding when displaying the QR code and/or challenge code to the users on their webpage.

QR Code deeplinking specifications

To support mobile users, DSAPs are also required to render the QR code with the mobile app links (deep links) following the format below.

For production:

Platform

Android

intent://app.singpass.gov.sg/docsign?sign_ref=<sign-ref>#Intent;scheme=https;package=sg.ndi.sp;S.browser_fallback_url=https://app.singpass.gov.sg/docsign;end

iOS

https://app.singpass.gov.sg/docsign?sign_ref=<sign-ref>

For staging:

Platform

Android

intent://stg-app.singpass.gov.sg/docsign?sign_ref=<sign-ref>#Intent;scheme=https;package=sg.ndi.sp.dev;S.browser_fallback_url=https://stg-app.singpass.gov.sg/docsign;end

iOS

https://stg-app.singpass.gov.sg/docsign?sign_ref=<sign-ref>

The new staging domain stg-app.singpass.gov.sg will only take effect from 18 Mar 2025. In the meantime, RP must use app.singpass.gov.sg for both staging and production.

Frequently Asked Questions (FAQs)

Question: Are DSAPs allowed to cache an end-user’s public X.509 Certificate beyond the TTL of a signing-session (sign_ref) to cater for better user experience?

Introduction of anism

Update to to support new staging app

Update to

Updated to indicate that ; onboarding for v1 no longer supported

JWT

JWT

The webhook server must be configured to present the full certificate chain to Singpass when Singpass invokes the notification webhook endpoints. This can be verified using a tool like . Please note that your cert should not be a self-signed certificate.

This is deprecated in favour of

For all DSS APIs, DSAPs will need to authenticate themselves using their base64-encoded client_id and client_secret via the scheme in the following format:

A document signing session is only valid for a short amount of time. The expiry of a signing session can be found via the expires_at response field. When a sign session expires, Singpass will delete it from storage and calls to will result in a SIGN_REF_NOT_FOUND error. Also, any attempts to scan a doc signing QR code or sign a doc hash will fail.

Please refer to

The DSAP must invoke this API only after it has received the user’s digital signing certificate through its notification webhook endpoint. See Steps 6, 7 and 8 of the for more details about what DSAPs need to do before invoking this endpoint.

The hash of the document to be signed by the user. Refer to for more details.

For other errors, please refer to

Integrating parties can verify the signature of a JWT from Singpass by acquiring the signing public key from this endpoint. More information about a JSON Web Key (JWK) endpoint can be found .

Public keys returned from this endpoint could be in random sequence or rotated for security enhancement. For more information, please refer to

It should expect a in the request body.

It should authenticate incoming calls using the , accepting only the client_notification_token given to Singpass during session initialisation.

For non-repudiation purposes, Singpass will sign all JWTs sent to DSAPs webhook with its signing key. DSAPs can retrieve the corresponding public keys for verification from

The hash of the document to be signed by the user. Refer to for more details.

The signature of the document hash, signed by the user. Refer to for more details.

Error code representing an error. Must be one of the values from the list of

Singpass will retry on 502, 503 and 504. Refer to

DSAPs must use to do the status verification against NCA. The OCSP response must be embedded in the signed document.

The size is large so we do not recommend using to verify the cert status to avoid large signed document file sizes.

DSAPs are expected to use the received user cert and generate a document hash that can later be digitally signed (locally) to form a compliant signature.

The signature follows the and will be hex-encoded.

DSAPs are expected to then generate a compliant signature using this.

Question: Since the webhook is defined as asynchronous and non-blocking, are there any constraints on when a DSAP should invoke the ?

Answer: Yes. The agreed average response time between the start of the webhook and the invocation of the hash endpoint must be 8 seconds. This 8-second interval correlates to the period that an end-user has to wait after scanning the QR (till he/she receives a "Signing Challenge"). While waiting for the "Signing Challenge" (which is provided by a DSAP), the end-user will encounter a loading/ spinner screen.

Answer: Although it is technically possible for DSAPs to cache an end-user’s public certificate beyond the TTL of a signing-session (sign_ref), Singpass does not condone such a practice as it infringes Data Protection Policies. i.e. Lack of end-user’s consent in providing his/her personal information to a third-party site/application ().

The will proceed to reject any requests of such nature if an invalid signing-reference ID (sign_ref) is provided. Repeated attempts to guess a signing-reference ID (sign_ref) will be logged and recognised by Singpass as a malicious security event.

SSL Labs
authenticating via JSON Web Tokens.
basic authentication
here
JSON Web Tokens (JWT)
Bearer authentication scheme
Online Certificate Status Protocol (OCSP)
Certificate Revocation List (CRL) file
CRL
PAdES-LTV/LTA
ASN.1/DER format
PAdES-LTV/LTA
https://www.singpass.gov.sg/singpass/common/privacystatement
/doc-signing-sessions/<sign-ref>/hash
General Error Response.
flow diagram
General Error Response.
Caching and key rotation.
/.well-known/keys.json.
user cert notification
/doc-signing-sessions/<sign-ref>/hash endpoint
user cert notification
/doc-signing-sessions/<sign-ref>/hash endpoint
Other DSAP Requirements
V3 is released
https://staging.sign.singpass.gov.sg/api/v1/*
(New)
https://app.sign.singpass.gov.sg/api/v1/*
(New)
https://static.staging.sign.singpass.gov.sg/.well-known/keys.json
https://static.app.sign.singpass.gov.sg/.well-known/keys.json
Document Hash Specifications
JWT as the preferred authentication mech
QR Code deeplinking specifications
Document Hash Specifications
Document Hash Signature Specifications
v
alid error codes.
Retry Settings.
latest documentation for V3
Document signing flow