Partner API

By request

Read access to the Schemes.sg catalogue, so partner organisations can surface the right scheme inside their own product.

Request accesshttps://asia-southeast1-schemessg.cloudfunctions.net/partner_api

Getting access

This is not a self-serve API. We work with a small number of partner organisations, and each key is issued by hand so we know who is using the data and can reach them if something changes.

Before a key is issued, we confirm our terms of use and privacy policy cover sharing scheme data with your organisation. You will get a sandbox key first, pointed at our development data, so you can build and test before touching anything live.

Quick start

One request, to check your key works and see the shape of a scheme.

Request
cURL
curl "https://asia-southeast1-schemessg.cloudfunctions.net/partner_api/v1/schemes?limit=1" \
  -H "X-API-Key: $SCHEMES_API_KEY"

Authentication

Every request carries your key in a header. There is no token exchange, no OAuth dance, and no expiry. Send it as X-API-Key.

Keep the key on your server. It is not safe in a browser, a mobile app, or anything a user can read, because it grants your whole quota to whoever holds it.
Header
HTTP
X-API-Key: sk_schemes_xxxxxxxxxxxxxxxxxxxxxxxx

Base URL and versioning

The version is a path segment, so a future version can ship alongside this one without changing any URL you have already built against.

There is one version today. A request with no version, or an unknown one, returns 404 rather than quietly falling back to v1.

base
HTTP
https://asia-southeast1-schemessg.cloudfunctions.net/partner_api/v1

Operations

Three read operations. One key covers all of them.

List schemes

GET/v1/schemes

Page through active schemes. Pass at most one filter at a time. Results exclude retired and inactive schemes.

Query parameters

categorystringoptional
One of: Financial Assistance, Family & Children, Health & Wellbeing, Housing & Food, Education, Employment & Training, Seniors & Caregiving, Disability & Transport, Legal & Safety, Community Support. Case-insensitive, but the name must match exactly — a slug such as "financial-assistance" is rejected. Cannot be combined with agency or area. For example Financial Assistance
agencystringoptional
Filter by the agency that runs the scheme. Cannot be combined with category or area. For example MSF
areastringoptional
Filter by planning area. Cannot be combined with category or agency. For example BEDOK
limitintegeroptional
Schemes per page. Defaults to 10, capped at 50. For example 20
cursorstringoptional
Opaque cursor from a previous response's next_cursor. Pass it back exactly as received; a modified or truncated cursor returns 400 rather than silently restarting from the first page. Omit for the first page.
Request
cURL
curl "https://asia-southeast1-schemessg.cloudfunctions.net/partner_api/v1/schemes?category=Financial%20Assistance&limit=2" \
  -H "X-API-Key: $SCHEMES_API_KEY"
Response
JSON
{
  "data": [
    {
      "scheme_id": "0kZ2mQ1xVbN4pR7t",
      "scheme": "ComCare Short-to-Medium-Term Assistance",
      "description": "Monthly cash assistance for households ...",
      "summary": "Monthly cash help while you get back on your feet.",
      "eligibility": "Singapore Citizen or PR, little or no income ...",
      "who_is_it_for": ["Low-income households"],
      "what_it_gives": ["Monthly cash assistance", "Household support"],
      "scheme_type": ["Financial Assistance"],
      "agency": "Ministry Of Social And Family Development",
      "link": "https://www.msf.gov.sg/...",
      "address": "512 Thomson Road",
      "phone": "1800 222 0000",
      "email": "enquiries@msf.gov.sg",
      "service_area": "Nationwide",
      "planning_area": ["BEDOK", "TAMPINES"],
      "image": "https://.../comcare.png",
      "status": "active"
    }
  ],
  "next_cursor": "eyJkb2NfaWQiOiIwa1oy...",
  "has_more": true,
  "total_count": 214
}

Retrieve a scheme

GET/v1/schemes/{scheme_id}

Fetch one scheme by id. Retired and inactive schemes return 404; a scheme retired by merging into another carries the new id.

Path parameters

scheme_idstringrequired
The scheme's id, as returned in scheme_id by list or search. For example 0kZ2mQ1xVbN4pR7t
Request
cURL
curl "https://asia-southeast1-schemessg.cloudfunctions.net/partner_api/v1/schemes/0kZ2mQ1xVbN4pR7t" \
  -H "X-API-Key: $SCHEMES_API_KEY"
Response
JSON
{
  "data": {
    "scheme_id": "0kZ2mQ1xVbN4pR7t",
    "scheme": "ComCare Short-to-Medium-Term Assistance",
    "description": "Monthly cash assistance for households ...",
    "eligibility": "Singapore Citizen or PR, little or no income ...",
    "agency": "Ministry Of Social And Family Development",
    "link": "https://www.msf.gov.sg/...",
    "status": "active"
  }
}

Search schemes

POST/v1/schemes/search

Rank schemes against a natural-language description of someone's situation. Same retrieval the Schemes.sg assistant uses, without the conversational layer.

Body parameters

querystringrequired
Plain-language description of the situation, not keywords. Longer is better. For example retired, living alone, struggling with medical bills
limitintegeroptional
Results per page. Defaults to 20, capped at 50. For example 10
cursorstringoptional
Opaque cursor from a previous response's next_cursor. Pass it back exactly as received; a modified or truncated cursor returns 400 rather than silently restarting from the first page. Omit for the first page.
Request
cURL
curl -X POST "https://asia-southeast1-schemessg.cloudfunctions.net/partner_api/v1/schemes/search" \
  -H "X-API-Key: $SCHEMES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "retired, living alone, struggling with medical bills",
    "limit": 10
  }'
Response
JSON
{
  "data": [
    {
      "scheme_id": "7bQ4rT2yWcM9nL3v",
      "scheme": "MediFund",
      "summary": "Help with hospital bills you still cannot afford.",
      "agency": "Ministry Of Health",
      "scheme_type": ["Health & Wellbeing"],
      "status": "active"
    }
  ],
  "next_cursor": null,
  "has_more": false,
  "total_count": 8
}

Scheme fields

Every scheme we return carries exactly these fields, whether it came from list, retrieve, or search. A field with no value is null rather than absent, so the set of keys never changes. A few fields hold either a single string or an array of strings, depending on the scheme — check the type column and handle both.

Scheme fields
FieldType
scheme_idstring
schemestring
descriptionstring
summarystring
eligibilitystring
who_is_it_forstring[]
what_it_givesstring[]
scheme_typestring[]
agencystring
linkstring
addressstring | string[]
phonestring | string[]
emailstring | string[]
service_areastring
planning_areastring | string[]
imagestring
statusstring

We hold other fields internally, for review workflow and ranking. Those are deliberately not part of this contract, so our internal changes cannot break your integration.

Errors

Every failure returns the same envelope, so you can branch on error.code and never parse a message.

Errors
StatusCodeWhat it means
400invalid_requestThe parameters are wrong. The message names which one.
401missing_keyNo X-API-Key header was sent.
401invalid_keyThe key is not one we issued.
403revoked_keyThe key was valid and has been turned off. Talk to us.
404not_foundNo such scheme, or it is no longer published.
404scheme_retiredThe scheme was retired and merged. The body carries merged_into.
404unsupported_versionThe version segment is missing or unknown.
405method_not_allowedRight path, wrong HTTP method.
429rate_limitedYour per-minute budget is spent. Retry-After says when.
500internal_errorSomething broke on our side. Safe to retry.
Response
JSON
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit of 600 requests/minute exceeded"
  }
}

Rate limits

Each partner gets a per-minute budget, shared across all three operations: spending it on list also spends it for search. Every response tells you where you stand, so you never have to discover the limit by hitting it.

X-RateLimit-Limit
Your budget, in requests per minute.
X-RateLimit-Remaining
What is left in the current minute.
Retry-After
Seconds to wait. Only sent with a 429.

When a scheme goes away

Schemes close, and some are folded into a replacement. If you store scheme ids, handle this case: a retired scheme that was merged returns 404 with the id that replaced it, so you can follow the change instead of silently dropping the record.

404
JSON
{
  "error": {
    "code": "scheme_retired",
    "message": "Scheme was retired and merged into another scheme",
    "merged_into": "9fH1jK8sZxC5vB2n"
  }
}