diff --git a/core/badge-urls/make-badge-url.js b/core/badge-urls/make-badge-url.js
index 3fd23042e6d56e3e187f1e6ea3ae489cae558314..f6e891ac3fa44b18d7f3c282cf2201abc7c7e13a 100644
--- a/core/badge-urls/make-badge-url.js
+++ b/core/badge-urls/make-badge-url.js
@@ -71,6 +71,36 @@ function staticBadgeUrl({
   return `${baseUrl}/badge/${path}.${format}${suffix}`
 }
 
+function queryStringStaticBadgeUrl({
+  baseUrl = '',
+  label,
+  message,
+  color,
+  labelColor,
+  style,
+  namedLogo,
+  logoColor,
+  logoWidth,
+  logoPosition,
+  format = 'svg',
+}) {
+  // schemaVersion could be a parameter if we iterate on it,
+  // for now it's hardcoded to the only supported version.
+  const schemaVersion = '1'
+  const suffix = `?${queryString.stringify({
+    label,
+    message,
+    color,
+    labelColor,
+    style,
+    logo: namedLogo,
+    logoColor,
+    logoWidth,
+    logoPosition,
+  })}`
+  return `${baseUrl}/static/v${schemaVersion}.${format}${suffix}`
+}
+
 function dynamicBadgeUrl({
   baseUrl,
   datatype,
@@ -109,5 +139,6 @@ module.exports = {
   badgeUrlFromPattern,
   encodeField,
   staticBadgeUrl,
+  queryStringStaticBadgeUrl,
   dynamicBadgeUrl,
 }
diff --git a/core/badge-urls/make-badge-url.spec.js b/core/badge-urls/make-badge-url.spec.js
index 3ca61b9fcccaf73a2ff39eb7a6b763facb23fe6d..55931b9436c92c361bce668f0d40a91b3bcfc893 100644
--- a/core/badge-urls/make-badge-url.spec.js
+++ b/core/badge-urls/make-badge-url.spec.js
@@ -6,6 +6,7 @@ const {
   badgeUrlFromPattern,
   encodeField,
   staticBadgeUrl,
+  queryStringStaticBadgeUrl,
   dynamicBadgeUrl,
 } = require('./make-badge-url')
 
@@ -81,6 +82,35 @@ describe('Badge URL generation functions', function() {
     }).expect('/badge/-blue-blue.svg')
   })
 
+  test(queryStringStaticBadgeUrl, () => {
+    // the query-string library sorts parameters by name
+    given({
+      label: 'foo',
+      message: 'bar',
+      color: 'blue',
+      style: 'flat-square',
+    }).expect(
+      '/static/v1.svg?color=blue&label=foo&message=bar&style=flat-square'
+    )
+    given({
+      label: 'foo Bar',
+      message: 'bar Baz',
+      color: 'blue',
+      style: 'flat-square',
+      format: 'png',
+      namedLogo: 'github',
+    }).expect(
+      '/static/v1.png?color=blue&label=foo%20Bar&logo=github&message=bar%20Baz&style=flat-square'
+    )
+    given({
+      label: 'Hello World',
+      message: 'Привет Мир',
+      color: '#aabbcc',
+    }).expect(
+      '/static/v1.svg?color=%23aabbcc&label=Hello%20World&message=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%20%D0%9C%D0%B8%D1%80'
+    )
+  })
+
   test(dynamicBadgeUrl, () => {
     const dataUrl = 'http://example.com/foo.json'
     const query = '$.bar'
diff --git a/core/base-service/coalesce-badge.js b/core/base-service/coalesce-badge.js
index 30819fb81485f51ebc3912bafb26b2b8d09d210f..68340fe47ac1a39cee038864bb553f8ffb3f6bc4 100644
--- a/core/base-service/coalesce-badge.js
+++ b/core/base-service/coalesce-badge.js
@@ -62,7 +62,7 @@ module.exports = function coalesceBadge(
     labelColor: overrideLabelColor,
   } = overrides
 
-  // Only use the legacy properties of the new ones are not provided
+  // Only use the legacy properties if the new ones are not provided
   if (typeof overrideColor === 'undefined') {
     overrideColor = legacyOverrideColor
   }
diff --git a/frontend/components/usage.js b/frontend/components/usage.js
index f323bfa2374adc27602386003c733c35a05e2be9..54485d64c4132a36518c4d79243f58a2383ef04e 100644
--- a/frontend/components/usage.js
+++ b/frontend/components/usage.js
@@ -179,12 +179,17 @@ export default class Usage extends React.PureComponent {
 
         <VerticalSpace />
 
+        <p>Using dash "-" separator</p>
+        <p>
+          <Snippet snippet={`${baseUrl}/badge/<LABEL>-<MESSAGE>-<COLOR>.svg`} />
+        </p>
+        {this.constructor.renderStaticBadgeEscapingRules()}
+        <p>Using query string parameters</p>
         <p>
           <Snippet
-            snippet={`${baseUrl}/badge/<SUBJECT>-<STATUS>-<COLOR>.svg`}
+            snippet={`${baseUrl}/static/v1.svg?label=<LABEL>&message=<MESSAGE>&color=<COLOR>`}
           />
         </p>
-        {this.constructor.renderStaticBadgeEscapingRules()}
 
         <H3 id="colors">Colors</H3>
         <p>
diff --git a/services/static-badge/query-string-static.service.js b/services/static-badge/query-string-static.service.js
new file mode 100644
index 0000000000000000000000000000000000000000..1236d505417e5bf05ddde6fb7077e7d901066bc0
--- /dev/null
+++ b/services/static-badge/query-string-static.service.js
@@ -0,0 +1,32 @@
+'use strict'
+
+const Joi = require('joi')
+const { BaseStaticService, InvalidParameter } = require('..')
+
+const queryParamSchema = Joi.object({
+  message: Joi.string().required(),
+}).required()
+
+module.exports = class QueryStringStaticBadge extends BaseStaticService {
+  static get category() {
+    return 'other'
+  }
+
+  static get route() {
+    return {
+      format: 'static/v([0-9])',
+      capture: ['schemaVersion'],
+      // All but one of the parameters are parsed via coalesceBadge. This
+      // reuses what is the override behaviour for other badges.
+      queryParamSchema,
+    }
+  }
+
+  handle(namedParams, queryParams) {
+    if (namedParams.schemaVersion !== '1') {
+      throw new InvalidParameter({ prettyMessage: 'Invalid schemaVersion' })
+    }
+
+    return { message: queryParams.message }
+  }
+}
diff --git a/services/static-badge/query-string-static.tester.js b/services/static-badge/query-string-static.tester.js
new file mode 100644
index 0000000000000000000000000000000000000000..6701d703455c1ab0ab290a31bd857702e469f2e8
--- /dev/null
+++ b/services/static-badge/query-string-static.tester.js
@@ -0,0 +1,39 @@
+'use strict'
+
+const t = (module.exports = require('../tester').createServiceTester())
+
+t.create('Missing message')
+  .get('/static/v1.json?label=label&message=&color=blue&style=_shields_test')
+  .expectJSON({
+    name: 'label',
+    value: 'invalid query parameter: message',
+    color: 'red',
+  })
+
+t.create('Missing label')
+  .get('/static/v1.json?label=&message=message&color=blue&style=_shields_test')
+  .expectJSON({ name: '', value: 'message', color: 'blue' })
+
+t.create('Case is preserved')
+  .get(
+    '/static/v1.json?label=LiCeNsE&message=mIt&color=blue&style=_shields_test'
+  )
+  .expectJSON({ name: 'LiCeNsE', value: 'mIt', color: 'blue' })
+
+t.create('Set color')
+  .get(
+    '/static/v1.json?label=label&message=message&color=yellow&style=_shields_test'
+  )
+  .expectJSON({ name: 'label', value: 'message', color: 'yellow' })
+
+t.create('Set color with a number')
+  .get(
+    '/static/v1.json?label=label&message=message&color=123&style=_shields_test'
+  )
+  .expectJSON({ name: 'label', value: 'message', color: '#123' })
+
+t.create('Set label')
+  .get(
+    '/static/v1.json?label=mylabel&message=message&color=blue&style=_shields_test'
+  )
+  .expectJSON({ name: 'mylabel', value: 'message', color: 'blue' })