A Singapore Government Agency Website

GovWallet Group Assist (Group Checkout) API (1.0.0)

Download OpenAPI specification:Download

Group Assist (group checkout) API used by MCCY Culture Pass.

A caller submits a batch of up to 50 per-NRIC transactions in one call. The call is asynchronous: the service persists a workflow, returns a workflowId immediately, and processes the batch on background workers. The outcome is retrieved by polling POST /api/workflow/get.

Transport envelope

Every request and response on these endpoints is wrapped in a JWE/JWS envelope.

Direction Content-Type Body Inner
Request application/x-www-form-urlencoded payload=<JWE> business JSON, RSA-OAEP-512 to GovWallet's enc key
Success application/json {"payload": "<JWE>"} JWE to the campaign's registered key, wrapping a GovWallet-signed JWS
Error application/json {"payload": "<JWS>"} signed only, not encrypted — claims are {"error": "..."}

The response JWS adds iss, iat and nbf claims alongside the business fields — that is why enquiry samples show iss: non-prd.dist.wallet.gov.sg next to workflowId/state/result.

GET /.well-known/jwks.json publishes both keys: RSA use: "enc" for request encryption, EC P-256 use: "sig" for response verification.

How to read this file

Every request and response below is documented in its decrypted form — the JSON that goes inside the envelope described above, not the raw HTTP body. This is for readability. The EncryptedEnvelope and SignedEnvelope schemas describe the real bodies.

To send a documented request: serialise the object to JSON, encrypt it with RSA-OAEP-512 to the use: "enc" key from GET /.well-known/jwks.json, and POST the compact JWE as application/x-www-form-urlencoded in a single field — payload=<JWE>. Any other content type, or a missing payload field, is rejected.

To read a documented response: the body is always the single-field wrapper {"payload": "<compact token>"}. Decrypt the JWE with the private key registered for your campaign, verify the resulting JWS against the use: "sig" key from the JWKS endpoint, then read its claims. Error responses skip the decryption step — their payload is a bare JWS.

Because both directions are documented as plaintext, generated clients and Swagger UI's "Try it out" will not work against this spec without adding the envelope steps yourself.

Authentication and authorisation

Two independent layers, both required on every request:

  1. OAuth2 client-credentials bearer token (AWS Cognito). Each endpoint requires a specific scope; a token without it is rejected before the body is read.
  2. JWE envelope. The decrypted campaign resolves the campaign and the caller's registered encryption key, so campaign is mandatory on every request. Responses are encrypted to the key registered for that campaign.

Tenancy is enforced per campaign: POST /api/workflow/get returns 404 when the requested workflow exists but belongs to a different campaign, deliberately making it indistinguishable from a workflow that does not exist.

Campaign naming

Campaign names are environment-suffixed — mccy-culture-pass-stg, mccy-culture-pass-prd. Examples throughout this file use the staging form. The name must match an existing campaign or intake returns campaign not found.

Group Assist

Submit a batch of group-checkout transactions.

Submit a batch of group-checkout transactions

Accepts up to 50 transactions, each keyed by hashNric, and queues them for asynchronous processing. Returns a workflowId used for later enquiry.

Idempotency — nonce is unique per campaign. Replaying a request with a nonce already seen for that campaign does not create a second workflow; the existing workflowId is returned with status 200 instead of 202.

Partner cart transaction id — GovWallet namespaces the supplied partnerCartTxnId by prefixing it with batch_payment- on intake. The prefix is applied idempotently: an id that already carries it is left untouched. Downstream records carry the prefixed id.

Authorizations:
oauth2ClientCredentials
Request Body schema: application/json
required

Shown decrypted. The actual request body is application/x-www-form-urlencoded with a single field, payload=<JWE>, whose plaintext is the JSON object below encrypted with RSA-OAEP-512 to the use: "enc" key from the JWKS endpoint.

nonce
required
string

Unique per campaign; the idempotency key for the batch. Replaying a nonce returns the workflow created the first time.

exp
required
integer <int64>

Expiry as a Unix timestamp in seconds. Must be present and strictly in the future at the time GovWallet processes the request.

iss
required
string <uri>

Issuer identifying the calling agency. Must be registered against campaign — GovWallet provisions this value.

partnerIss
required
string <uri>

Issuer identifying the merchant/partner the payment is made to. Must be registered against campaign; it resolves the merchant used for the downstream 2C2P call.

tags
Array of strings

Free-form labels attached to the batch.

partnerCartTxnId
required
string

Partner's own identifier for the cart/transaction group. GovWallet prefixes it with batch_payment- on intake; supply the bare id.

required
Array of objects (BatchTransaction) [ 1 .. 50 ] items

One entry per beneficiary. At least 1, at most 50. hashNric must be unique within the batch.

campaign
required
string

GovWallet campaign name, environment-suffixed. Must exist or intake returns campaign not found.

Responses

Request samples

Content type
application/json
{
  • "nonce": "sample-nonce",
  • "exp": 1234567890,
  • "tags": [
    ],
  • "partnerCartTxnId": "97183f96-b9e1-4c93-97ae-03d04ff08104",
  • "transactions": [
    ],
  • "campaign": "mccy-culture-pass-stg"
}

Response samples

Content type
application/json
{
  • "workflowId": "968de5dd-558f-47ee-a032-a3217fc373a8"
}

Workflow

Enquire on the state and result of a previously submitted batch.

Enquire on a batch job / workflow

Returns the current state of a workflow and, once state is completed, the per-transaction results.

The workflow must belong to the campaign supplied in the request; a mismatch is reported as 404 and is indistinguishable from a workflow that does not exist.

Authorizations:
oauth2ClientCredentials
Request Body schema: application/json
required

Shown decrypted. The actual request body is application/x-www-form-urlencoded with a single field, payload=<JWE>, whose plaintext is the JSON object below encrypted with RSA-OAEP-512 to the use: "enc" key from the JWKS endpoint.

campaign
required
string

Must match the campaign the workflow was created under.

workflowId
required
string <uuid>

The workflowId returned by POST /api/batch/create.

Responses

Request samples

Content type
application/json
{
  • "campaign": "mccy-culture-pass-stg",
  • "workflowId": "eee88efd-e82a-476e-8864-52b1e95ebc80"
}

Response samples

Content type
application/json
Example

Non-terminal. result is absent. createdAt and updatedAt are still identical because nothing has advanced the workflow yet.

{
  • "workflowId": "b188cbfa-bc94-4bb2-8e30-98c8518c5ae7",
  • "state": "queued",
  • "createdAt": "2026-07-24T01:56:39Z",
  • "updatedAt": "2026-07-24T01:56:39Z",
  • "iss": "non-prd.dist.wallet.gov.sg",
  • "iat": 1784879567,
  • "nbf": 1784879567
}
Chat with me!
Bot Launcher