Returning.AIDevelopers
v1

API reference / Gamification / Match Predictions

.md

Create match prediction

Create a match prediction as a draft in the community that owns your API key, ready to edit and then publish.

Last updated 26 Sep 2026API v1

Method
POST
Path
https://api.returning.ai/v1/match-predictions
Permission
matchPredictions
Retries
Idempotency-Key required; reuse it only for the same body

When to use this

  • A fixture is announced and you want a prediction game for it.
  • Your sports data feed creates one match prediction per fixture, keyed by your own fixture ID.
  • You want to set up the teams, times and rewards now and publish later.

Authentication#

Header
Authorization: Bearer <API_KEY>
Permission
matchPredictionsShown in the dashboard as “Match Prediction”

Use a Community API key with matchPredictions, shown in the dashboard as Match Prediction, and keep it on your server. The key decides the community: you only see and change match predictions in that community, and an ID from another community returns 404, the same as an unknown ID. Personal API keys are rejected with 403.

Behaviour#

api.returning.ai doesn't serve this route yet: requests return an empty 404. Ask Returning.AI before you build on it.

A new match prediction is a draft: traders can't see it until you publish it. Drafts also appear with your other mini-games in the dashboard, where your team can edit or delete them, and match predictions your team creates there are returned by these endpoints too.

Request#

Headers#

Authorization#stringREQUIRED
Community API key with matchPredictions.

RuleBearer <API_KEY>

Idempotency-Key#stringREQUIRED
A unique key you create for this match prediction, such as a UUID. Reuse it only to retry the same body.

Rule1-255 characters

Eg"3f9c2a7e-1b4d-4e8a-9c61-2d5f7a8b9e10"

Content-Type#stringREQUIRED
Request body format. Anything else returns 415.

Ruleapplication/json

X-Request-Id#stringOPTIONAL
Your own ID for this request, returned in meta.requestId. Without it, a req_... ID is generated.

Body#

Required: title, teamA.name, teamB.name, predictionStartAt, lockAt, kickoffAt, both reward tiers, entryCost and viewPermission. Every other field is optional, and a field that isn't listed here is rejected at any level.

Send times as ISO 8601 in UTC ending in Z, such as 2026-10-10T19:00:00.000Z; an offset such as +08:00 is rejected. predictionStartAt must be at or before lockAt, lockAt at or before kickoffAt, and kickoffAt in the future.

Send your fixture ID as externalReference. It is unique in your community, so a repeated create returns 409 EXTERNAL_REFERENCE_CONFLICT instead of a second match. Role and user IDs in viewPermission must belong to your community.

title#stringREQUIRED
The match title traders see.

Rule1-256 characters, trimmed

Eg"Australia vs New Zealand"

description#stringOPTIONAL
Longer text for traders.

RuleUp to 10,000 characters

Eg"Predict the final score."

externalReference#stringOPTIONAL
Your own fixture ID. Unique in your community, so it is the safest way to find the match again.

Rule1-128 characters, trimmed

Eg"provider-fixture-123"

teamA#objectREQUIRED
The first team. Replaced as a whole.

Eg{ ... }

name#stringREQUIRED
Team name.

Rule1-128 characters

Eg"Australia"

imageUrl#stringOPTIONAL
Team logo URL.

RuleA URL, up to 2,048 characters

Eg"https://cdn.example.com/teams/australia.png"

teamB#objectREQUIRED
The second team. Replaced as a whole.

Eg{ ... }

name#stringREQUIRED
Team name.

Rule1-128 characters

Eg"New Zealand"

imageUrl#stringOPTIONAL
Team logo URL.

RuleA URL, up to 2,048 characters

Eg"https://cdn.example.com/teams/new-zealand.png"

predictionStartAt#stringREQUIRED
When traders can start predicting.

RuleISO 8601 in UTC ending in Z; at or before lockAt

Eg"2026-10-01T08:00:00.000Z"

lockAt#stringREQUIRED
When predictions close.

RuleISO 8601 in UTC ending in Z; at or before kickoffAt

Eg"2026-10-10T18:55:00.000Z"

kickoffAt#stringREQUIRED
When the match starts. You can settle only after this time.

RuleISO 8601 in UTC ending in Z; in the future

Eg"2026-10-10T19:00:00.000Z"

scoreBasis#stringOPTIONAL
Which score you will settle on. Defaults to regulation.

Ruleregulation or extra_time

Eg"regulation"

rewards#objectREQUIRED
What winners earn. Send both tiers.

Eg{ ... }

correctResult#objectREQUIRED
Paid for picking the right result: team A, team B or a draw.

Eg{"coins": 100, "xp": 50}

coins#integerREQUIRED
Coins.

RuleWhole number, 0-1,000,000

Eg100

xp#integerREQUIRED
XP.

RuleWhole number, 0-1,000,000

Eg50

exactScoreBonus#objectREQUIRED
Paid on top of correctResult when the called score is also exact.

Eg{"coins": 200, "xp": 100}

coins#integerREQUIRED
Coins.

RuleWhole number, 0-1,000,000

Eg200

xp#integerREQUIRED
XP.

RuleWhole number, 0-1,000,000

Eg100

entryCost#objectREQUIRED
What a trader pays to predict. Winners get it back at settlement, and everyone gets it back if you void.

Eg{"enabled": false, "coins": 0}

enabled#booleanREQUIRED
true to charge coins for each prediction.

Egfalse

coins#integerREQUIRED
Coins per prediction.

RuleWhole number; 0 when enabled is false

Eg0

viewPermission#objectREQUIRED
Who can see the match once it is published. Can be empty on a draft; publishing needs at least one role or user.

Eg{"roleIds": ["66f000000000000000000806"], "userIds": []}

roleIds#string[]REQUIRED
Role IDs from your community. Traders with any of these roles can see it.

RuleRole IDs in your community

Eg["66f000000000000000000806"]

userIds#string[]REQUIRED
Platform user IDs, as strings, of traders who can see it.

RuleMembers of your community

Eg["3247779"]

curl --request POST \
  --url https://api.returning.ai/v1/match-predictions \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Idempotency-Key: 3f9c2a7e-1b4d-4e8a-9c61-2d5f7a8b9e10' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "Australia vs New Zealand",
    "description": "Predict the final score.",
    "externalReference": "provider-fixture-123",
    "teamA": {
      "name": "Australia",
      "imageUrl": "https://cdn.example.com/teams/australia.png"
    },
    "teamB": {
      "name": "New Zealand",
      "imageUrl": "https://cdn.example.com/teams/new-zealand.png"
    },
    "predictionStartAt": "2026-10-01T08:00:00.000Z",
    "lockAt": "2026-10-10T18:55:00.000Z",
    "kickoffAt": "2026-10-10T19:00:00.000Z",
    "scoreBasis": "regulation",
    "rewards": {
      "correctResult": {
        "coins": 100,
        "xp": 50
      },
      "exactScoreBonus": {
        "coins": 200,
        "xp": 100
      }
    },
    "entryCost": {
      "enabled": false,
      "coins": 0
    },
    "viewPermission": {
      "roleIds": ["66f000000000000000000806"],
      "userIds": []
    }
  }'

Response#

A 201 returns the whole match prediction, with status draft, isPublished false and version 1. Save data.id for every later call.

meta#objectALWAYS
Result details.

Eg{ ... }

status#stringALWAYS
Result of the request.

Rulesuccess

statusCode#integerALWAYS
The HTTP status, repeated.

Rule201

code#stringALWAYS
Machine-readable result code.

RuleMATCH_PREDICTION_CREATED

requestId#stringALWAYS
Your X-Request-Id if you sent one, otherwise a generated req_... ID. Quote it when you contact support.

Eg"req_66f00000000000000000000000000811"

message#stringALWAYS
Human-readable summary. Do not branch on it.

Eg"Match prediction created."

data#objectALWAYS
The new match prediction.

Eg{ ... }

id#stringALWAYS
The match prediction ID. Save it.

Rulemp_ and 24 hex characters

Eg"mp_66f000000000000000000801"

externalReference#string
Your own fixture ID. Left out when not set.
title#stringALWAYS
The match title traders see.
description#string
Longer text for traders. Left out when not set.
teamA#objectALWAYS
The first team.
name#stringALWAYS
Team name.
imageUrl#string
Team logo URL. Left out when not set.
teamB#objectALWAYS
The second team.
name#stringALWAYS
Team name.
imageUrl#string
Team logo URL. Left out when not set.
predictionStartAt#stringALWAYS
When traders can start predicting, in UTC. Milliseconds always read .000.
lockAt#stringALWAYS
When predictions close, in UTC.
kickoffAt#stringALWAYS
When the match starts, in UTC.
scoreBasis#stringALWAYS
Which score you settle on. Settlement uses the score you send either way.

Ruleregulation or extra_time

viewPermission#objectALWAYS
Who can see the match once it is published.
roleIds#string[]ALWAYS
Role IDs. Traders with any of these roles can see it.
userIds#string[]ALWAYS
Platform user IDs, as strings, of traders who can see it.
rewards#objectALWAYS
What winners earn.
correctResult#objectALWAYS
Paid for picking the right result: team A, team B or a draw.
coins#integerALWAYS
Coins.
xp#integerALWAYS
XP.
exactScoreBonus#objectALWAYS
Paid on top of correctResult when the called score is also exact.
coins#integerALWAYS
Coins.
xp#integerALWAYS
XP.
entryCost#objectALWAYS
What a trader pays to predict.
enabled#booleanALWAYS
true when predicting costs coins.
coins#integerALWAYS
Coins per prediction. 0 when enabled is false.
status#stringALWAYS
Always draft for a new match prediction.

Ruledraft

isPublished#booleanALWAYS
true once published.
acceptingPredictions#booleanALWAYS
true while the match is open and the time is between predictionStartAt and lockAt.
attemptCount#integerALWAYS
Predictions traders have submitted.
settlement#objectALWAYS
Always null here. Read the match with Get match prediction for its settlement totals.
version#integerALWAYS
Always 1 for a new match prediction. Send it with your first Patch match prediction.

Eg1

createdAt#stringALWAYS
When the match prediction was created.
updatedAt#stringALWAYS
When it last changed.
{
  "meta": {
    "status": "success",
    "statusCode": 201,
    "code": "MATCH_PREDICTION_CREATED",
    "requestId": "req_66f00000000000000000000000000811"
  },
  "message": "Match prediction created.",
  "data": {
    "id": "mp_66f000000000000000000801",
    "title": "Australia vs New Zealand",
    "teamA": {
      "name": "Australia",
      "imageUrl": "https://cdn.example.com/teams/australia.png"
    },
    "teamB": {
      "name": "New Zealand",
      "imageUrl": "https://cdn.example.com/teams/new-zealand.png"
    },
    "predictionStartAt": "2026-10-01T08:00:00.000Z",
    "lockAt": "2026-10-10T18:55:00.000Z",
    "kickoffAt": "2026-10-10T19:00:00.000Z",
    "scoreBasis": "regulation",
    "viewPermission": {
      "roleIds": ["66f000000000000000000806"],
      "userIds": []
    },
    "rewards": {
      "correctResult": {
        "coins": 100,
        "xp": 50
      },
      "exactScoreBonus": {
        "coins": 200,
        "xp": 100
      }
    },
    "entryCost": {
      "enabled": false,
      "coins": 0
    },
    "status": "draft",
    "isPublished": false,
    "acceptingPredictions": false,
    "attemptCount": 0,
    "settlement": null,
    "version": 1,
    "createdAt": "2026-09-27T09:00:00.000Z",
    "updatedAt": "2026-09-27T09:00:00.000Z",
    "externalReference": "provider-fixture-123",
    "description": "Predict the final score."
  }
}

Errors#

Every error carries its code in meta.code and the request's ID in meta.requestId. Validation errors list each problem in details, with a field, code and message. The API key checks (401, 403, 404 COMMUNITY_NOT_FOUND and 500 AUTHENTICATION_FAILED) return detail and solution instead. A 404 with an empty body means the route isn't available on api.returning.ai yet.

Fix the request10

404Fix the request
The body is empty: api.returning.ai doesn't serve this route yet. Ask Returning.AI before you build on it.
400MATCH_PREDICTION_VALIDATION_FAILEDFix the request
A field is missing, breaks its rule or isn't recognised; the times are out of order; kickoffAt isn't in the future; or entryCost.coins isn't 0 while entryCost.enabled is false. details lists each problem. A role or user in viewPermission that isn't in your community gives INVALID_REFERENCE, with message Match prediction configuration is invalid. Nothing was saved.
400READ_ONLY_FIELDFix the request
The request has a field the server sets, such as id, status, version or createdAt. details names it. Remove it.
400INVALID_JSONFix the request
The body is not valid JSON. Fix the syntax and send it again.
400IDEMPOTENCY_KEY_REQUIREDFix the request
Send an Idempotency-Key header with a unique value.
400IDEMPOTENCY_KEY_INVALIDFix the request
The Idempotency-Key is longer than 255 characters. Use a shorter key, such as a UUID.
415UNSUPPORTED_MEDIA_TYPEFix the request
Send the body as JSON with Content-Type: application/json.
401AUTHENTICATION_REQUIREDFix the request
The key is missing, invalid or expired. Send Authorization: Bearer <API_KEY> with a current Community API key.
403API_KEY_PERMISSION_DENIEDFix the request
The key lacks matchPredictions, or it is a personal key. Use a Community API key and add Match Prediction in Settings > Integration > API Keys.
409IDEMPOTENCY_KEY_CONFLICTFix the request
This Idempotency-Key was already used with a different body, or the first request with it is still running. Use a new key for a new body.

Fix the data02

404COMMUNITY_NOT_FOUNDFix the data
The community this key belongs to no longer exists. Contact Returning.AI support.
409EXTERNAL_REFERENCE_CONFLICTFix the data
Another match prediction in your community already has this externalReference. Find it with List match predictions instead of creating it again.

Retry with backoff04

429RATE_LIMITEDRetry with backoff
Your community is over its rate limit. Wait for the seconds in Retry-After, then retry.
500INTERNAL_ERRORRetry with backoff
The outcome is unclear. Look the match up with List match predictions and your externalReference, and create it again with a new key only if it isn't there.
500AUTHENTICATION_FAILEDRetry with backoff
The key could not be checked. Retry with backoff; nothing changed.
503MATCH_PREDICTION_FROZENRetry with backoff
Returning.AI has paused match prediction requests. Nothing changed. Retry later with backoff.
{
  "meta": {
    "status": "success",
    "statusCode": 201,
    "code": "MATCH_PREDICTION_CREATED",
    "requestId": "req_66f00000000000000000000000000811"
  },
  "message": "Match prediction created.",
  "data": {
    "id": "mp_66f000000000000000000801",
    "title": "Australia vs New Zealand",
    "teamA": {
      "name": "Australia",
      "imageUrl": "https://cdn.example.com/teams/australia.png"
    },
    "teamB": {
      "name": "New Zealand",
      "imageUrl": "https://cdn.example.com/teams/new-zealand.png"
    },
    "predictionStartAt": "2026-10-01T08:00:00.000Z",
    "lockAt": "2026-10-10T18:55:00.000Z",
    "kickoffAt": "2026-10-10T19:00:00.000Z",
    "scoreBasis": "regulation",
    "viewPermission": {
      "roleIds": ["66f000000000000000000806"],
      "userIds": []
    },
    "rewards": {
      "correctResult": {
        "coins": 100,
        "xp": 50
      },
      "exactScoreBonus": {
        "coins": 200,
        "xp": 100
      }
    },
    "entryCost": {
      "enabled": false,
      "coins": 0
    },
    "status": "draft",
    "isPublished": false,
    "acceptingPredictions": false,
    "attemptCount": 0,
    "settlement": null,
    "version": 1,
    "createdAt": "2026-09-27T09:00:00.000Z",
    "updatedAt": "2026-09-27T09:00:00.000Z",
    "externalReference": "provider-fixture-123",
    "description": "Predict the final score."
  }
}

Next step#

Publish match predictionPOST/v1/match-predictions/{matchPredictionId}/publishPublish the draft when it is ready, so the traders in viewPermission can see it.