Skip to content

auds-banner

AUDS - Arbitrary User Data Store

This API is currently in development and subject to change. Do not use in production.


1. Create userdata

Use the following endpoint to create userdata. The <freeform-key> can be any label you choose to categorize your data (e.g. tests, levels, maps, etc.).

POST https://auds.poki.io/v0/<your-poki-game-id>/userdata/<freeform-key>

Request body

{
  "data": {
    "tiles": [1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0],
    "note": "data in userdata is freeform, can be anything."
  },
  "values": {
    "levelname": "Test level",
    "type": "arena-1v1",
    "note": "'values' can only be key/value pairs where values can only be string, number, or boolean"
  }
}

Example request

const body = {
  data: {
    tiles: [1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0],
    note: 'data in userdata is freeform, can be anything.'
  },
  values: {
    levelname: 'Test level',
    type: 'arena-1v1',
    note: "'values' can only be key/value pairs where values can only be string, number, or boolean"
  }
};

const requestOptions = {
  method: 'POST',
  body: JSON.stringify(body),
};

fetch('https://auds.poki.io/v0/use-your-poki-game-id/userdata/tests', requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

Example response

{
  "id": "ce702oq1gkcvlv1tmlgg",
  "secret": "Qn8iO6bQVlGyVPkJhoi4oHwufb6GWgpgyedP5cO3fB39rzwTJZwg7N2n7GbLU3aG",
  "meta": {
    "revision": 1,
    "created_at": "2022-12-05T14:34:11.67798351Z",
    "expires_at": "2023-12-05T14:34:11.67798351Z",
    "expires_in": 31536000
  },
  "values": {
    "levelname": "Test level",
    "note": "'values' can only be key/value pairs where values can only be string, number, or boolean",
    "type": "arena-1v1"
  }
}

Returned secret

The response will include an id and a secret. The secret is never returned again, so make sure you store it if you plan to update this userdata later.


2. Fetch userdata by ID

Use this endpoint to retrieve a previously created userdata entry by its id.

GET https://auds.poki.io/v0/<your-poki-game-id>/userdata/<freeform-key>/<id>

Example request

fetch('https://auds.poki.io/v0/use-your-poki-game-id/userdata/tests/ce702oq1gkcvlv1tmlgg')
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

Example response

{
  "id": "ce702oq1gkcvlv1tmlgg",
  "meta": {
    "revision": 1,
    "created_at": "2022-12-05T14:34:11.677983Z",
    "expires_at": "2023-12-05T14:37:02.733083Z",
    "expires_in": 31536000
  },
  "values": {
    "levelname": "Test level",
    "note": "'values' can only be key/value pairs where values can only be string, number, or boolean",
    "type": "arena-1v1"
  },
  "data": {
    "note": "data in userdata is freeform, can be anything.",
    "tiles": [1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0]
  }
}


3. Get list of userdata

Use the following endpoint to list userdata. You can optionally filter and sort the results.

GET https://auds.poki.io/v0/<your-poki-game-id>/userdata/<freeform-key>?q=type:arena-1v1&sort=key&includedata

Supported query parameters

Parameter Description
q=key:value Filters the results by a values key. Only basic matching is supported right now. This will change.
q=<json> URL-encoded JSON query for advanced filters. Syntax and examples can be found here: https://github.com/poki/mongodb-filter-to-postgres
sort=key Sorts results ascending by the given values key.
sort=-key Sorts results descending by the given values key.
includedata Includes the data field in the returned items.
limit=n Only return n results (min 1, max 100)

Example request

fetch('https://auds.poki.io/v0/use-your-poki-game-id/userdata/tests?q=type:arena-1v1')
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

Example response

{
  "total": 1,
  "items": [
    {
      "id": "ce702oq1gkcvlv1tmlgg",
      "meta": {
        "revision": 1,
        "created_at": "2022-12-05T14:34:11.677983Z",
        "expires_at": "2023-12-05T14:34:11.677983Z",
        "expires_in": 31536000
      },
      "values": {
        "levelname": "Test level",
        "note": "'values' can only be key/value pairs where values can only be string, number, or boolean",
        "type": "arena-1v1"
      }
    }
  ]
}


4. Update userdata by ID with secret

To update userdata, you must supply the secret you received during creation, or your admin token through the Authorization header. This endpoint will only update keys you provide. Omitted fields remain unchanged.

POST https://auds.poki.io/v0/<your-poki-game-id>/userdata/<freeform-key>/<id>

Request body

{
  "secret": "<SECRET_RECEIVED_ON_CREATE>",
  "data": {
    "tiles": [1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1]
  },
  "values": {
    "levelname": "Test level (edited)",
    "type": "arena-1v1"
  }
}

Example request

const body = {
  secret: 'Qn8iO6bQVlGyVPkJhoi4oHwufb6GWgpgyedP5cO3fB39rzwTJZwg7N2n7GbLU3aG',
  data: {
    tiles: [1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1]
  },
  values: {
    levelname: 'Test level (edited)',
    type: 'arena-1v1'
  }
};

const requestOptions = {
  method: 'POST',
  body: JSON.stringify(body),
  // Or instead of the secret in the body:
  // headers: {
  //   'Authorization': 'AdminToken <your-admin-token>',
  // }
};

fetch('https://auds.poki.io/v0/use-your-poki-game-id/userdata/tests/ce702oq1gkcvlv1tmlgg', requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

Example response

{
  "id": "ce702oq1gkcvlv1tmlgg",
  "meta": {
    "revision": 2,
    "created_at": "2022-12-05T14:34:11.677983Z",
    "updated_at": "2022-12-05T14:41:58.223397772Z",
    "expires_at": "2023-12-05T14:41:58.223397772Z",
    "expires_in": 31536000
  },
  "values": {
    "levelname": "Test level (edited)",
    "type": "arena-1v1"
  }
}


5. Delete userdata by ID with secret

To delete userdata, you must supply the secret you received during creation, or your admin token through the Authorization header.

DELETE https://auds.poki.io/v0/<your-poki-game-id>/userdata/<freeform-key>/<id>

Request body

{
  "secret": "<SECRET_RECEIVED_ON_CREATE>"
}

Example request

const body = {
  secret: 'Qn8iO6bQVlGyVPkJhoi4oHwufb6GWgpgyedP5cO3fB39rzwTJZwg7N2n7GbLU3aG',
};

const requestOptions = {
  method: 'DELETE',
  body: JSON.stringify(body),
  // Or instead of the body:
  // headers: {
  //   'Authorization': 'AdminToken <your-admin-token>',
  // }
};

fetch('https://auds.poki.io/v0/use-your-poki-game-id/userdata/tests/ce702oq1gkcvlv1tmlgg', requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));


6. Increment a counter value

Use this endpoint to increment a numeric counter inside the values object. This is meant for public counters (e.g. play-count) and does not require the secret like the update endpoint does.

POST https://auds.poki.io/v0/<your-poki-game-id>/userdata/<freeform-key>/<id>/_increment?key=<value-key>

Notes

  • The key must contain count (e.g. play-count, count-score).
  • The existing value must be a number.
  • The counter increases by 1.
  • The revision does not change; only updated_at changes.
  • No request body is required.
  • No secret or Authorization header is required for this endpoint.

Example request

fetch('https://auds.poki.io/v0/use-your-poki-game-id/userdata/tests/ce702oq1gkcvlv1tmlgg/_increment?key=play-count', {
  method: 'POST'
})
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

Example response

{
  "id": "ce702oq1gkcvlv1tmlgg",
  "meta": {
    "revision": 1,
    "created_at": "2022-12-05T14:34:11.677983Z",
    "updated_at": "2022-12-05T14:41:58.223397772Z",
    "expires_at": "2023-12-05T14:41:58.223397772Z",
    "expires_in": 31536000
  },
  "values": {
    "levelname": "Test level",
    "play-count": 42
  }
}


7. Vote on a value

Use this endpoint to increment vote counters (e.g. up-vote, down-vote). Voting is limited to once per IP address, per value key, per day, and does not require the secret like the update endpoint does.

POST https://auds.poki.io/v0/<your-poki-game-id>/userdata/<freeform-key>/<id>/_vote?key=<value-key>

Notes

  • The existing value must be a number.
  • Voting is tracked by client IP and day; duplicate votes return 409.
  • The revision does not change; only updated_at changes.
  • No request body is required.
  • No secret or Authorization header is required for this endpoint.

Example request

fetch('https://auds.poki.io/v0/use-your-poki-game-id/userdata/tests/ce702oq1gkcvlv1tmlgg/_vote?key=up-vote', {
  method: 'POST'
})
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

Example response

{
  "id": "ce702oq1gkcvlv1tmlgg",
  "meta": {
    "revision": 1,
    "created_at": "2022-12-05T14:34:11.677983Z",
    "updated_at": "2022-12-05T14:41:58.223397772Z",
    "expires_at": "2023-12-05T14:41:58.223397772Z",
    "expires_in": 31536000
  },
  "values": {
    "levelname": "Test level",
    "up-vote": 33
  }
}


8. Authentication options

Update and delete endpoints accept three authentication methods:

  • secret in the request body (the default).
  • Authorization: AdminToken <your-admin-token> header.
  • Authorization: Bearer <poki-for-developers-jwt> header.

For Poki for Developers tokens, role=developer requires the token to include the team that owns the game. role=admin can manage any game. Unauthorized access returns 404 to avoid leaking record existence.


9. CORS and allowed origins

AUDS only allows browser requests from Poki and development domains:

  • localhost
  • 127.0.0.1
  • ::1
  • *.netlify.app
  • launch.playcanvas.com
  • playcanv.as
  • *.scf.usercontent.goog


10. Validation and error responses

Validation rules

  • <freeform-key> and values keys must match /[a-z][a-z0-9_-]{,31}/i (no double dashes).
  • <id> must match /^[0-9a-v]{20}$/.
  • values may only contain strings, numbers, or booleans (no nested objects).
  • data can be any JSON type.

Common error responses

  • 400 bad-request for invalid JSON payloads.
  • 400 invalid-url-params for invalid data type or id.
  • 400 invalid-values for invalid values keys or value types.
  • 400 invalid-key for disallowed increment keys.
  • 403 invalid-game for unknown game ids.
  • 404 not-found for missing entries or invalid increment targets.
  • 409 already-voted when the same IP votes on the same key twice in a day.


Final Notes

  • Secrets: Store the secret in a secure location (like localStorage) if you plan to update or delete this entry later. This API will never return the secret again.
  • Prototype: The q parameter will change in upcoming versions. Use with caution.
  • Freeform keys: The segment after /userdata/ is entirely up to you. For example, tests, levels, or players.
  • Admin token: All update (PATCH, PUT) and delete (DELETE) requests can also be made with a Authorization: AdminToken <your-admin-token> header instead of the secret in the request body.
  • Caching: GET responses can be cached briefly. Updates, deletes, increments, and votes invalidate the cache, so repeated GETs may not always refresh access logs.

Defold

There is a Defold Lua Module for AUDS available at: github.com/indiesoftby/defold-poki-auds