Recommander API

Recommander maintains a public-facing API for card recommendations. This page documents the available endpoints, request and response formats, error codes, and example usage.

The public release is hosted at https://api.recommander.cards/public-release. All endpoint paths below are relative to that base URL.

This API is intended for use by third-party developers, content creators, and anyone else interested in integrating Recommander’s card recommendations into their own projects. Whether you’re creating a deck-building tool, a content website, or just want to experiment with the data, the API provides a way to access Recommander’s insights programmatically.

We’re interested in hearing from you! If you have questions about using the API, want to discuss a specific use case, or anything else, please contact us on Discord.

Terms of Use

To ensure fair use and maintain the quality of our service, we ask that all API users adhere to the following guidelines:

  • Respect rate limits: Please do not exceed the specified request limits for each endpoint. If you need higher limits, contact us to discuss options.
  • Use data responsibly: The recommendations and data provided by the API are intended for personal and non-commercial use. If you wish to use the data for commercial purposes, please reach out to us.
  • Provide attribution: If you use Recommander’s API in your project, we ask that you provide appropriate attribution to Recommander as the source of the recommendations.
  • Do not scrape: Please do not scrape our website for data. Use the API endpoints provided for accessing information.
  • Contact us with questions: If you’re unsure about any aspect of using the API or want to discuss a specific use case, don’t hesitate to contact us.

Rate Limits

To ensure a stable and responsive experience for all users, the Recommander API enforces rate limits on incoming requests. The specific limits may vary by endpoint and user type, but generally, we allow a certain number of requests per minute or hour. If you exceed these limits, you will receive a 429 Too Many Requests response, and we ask that you wait before making additional requests. If you require higher limits for your project, please contact us to discuss your needs.

Data Sources

The Recommander API works on a data set derived from publicly available Commander decklists, primarily sourced from popular deck-building websites. We aggregate and analyze this data to generate card recommendations based on real-world deck-building trends and synergies. The API provides access to these recommendations, but does not expose the underlying decklist data directly.

We are committed to respecting the terms of service of the sites we source from and do not provide endpoints for scraping or bulk data access. Instead, we focus on delivering actionable insights through our recommendation endpoints while maintaining compliance with data usage policies.

At the request of our data sources, the API may serve a model that is trained on a subset of the available data, or that has certain limitations compared to our internal models.

API Specification

The recommendations API receives POST requests at /api/decks/recommend/top with a JSON body containing the commander, an optional partner, and the current deck. The body can also weight individual cards, and can choose which cards are ranked: the commanders’ color identity by default, or every card, a list you supply, or the cards from one set. The response includes a list of recommended cards with their names, Scryfall Oracle IDs, and recommendation scores. All responses are wrapped in a standard envelope that indicates success or failure and includes error messages when applicable.

Methods

POST/api/decks/recommend/top

Accepts a deck query and returns a list of recommendations. The response is wrapped in the standard API result envelope.

Base URLhttps://api.recommander.cards/public-release
OperationRecommendSlimPost
ResponseApiResult<RecommendResultTop>

Data Types

RecommendSlimQuery

The request payload for the recommendations endpoint.

FieldTypeRequiredNullableNotes
card_formatenumNoNoHow every card in the request is identified: the commanders, the deck, the keys of weighted_deck, and explicit candidates. One of oracle_id, scryfall_id, name, or set_collector_number, which is set|number with an optional |language (English when left off). Defaults to oracle_id.
commanderstringYesNoThe main commander identifier. At most 150 characters.
partnerstringNoYesOptional partner commander. At most 150 characters.
deckstring[]NoNoCards encoded using the selected card_format. At most 500 cards, each identifier at most 150 characters.
weighted_deckobjectNoYesCards mapped to a weight between -10 and 10, for how much each counts toward the recommendations. A card in deck counts 1.0 unless it is weighted here. A card listed only here is added to the deck. A negative weight counts against the cards usually played with that card. At most 500 cards, each identifier at most 150 characters.
candidate_stepRecommendSlimCandidateStepNoYesWhich cards are ranked. Leave it out to rank the cards in the commanders’ color identity.

RecommendSlimCandidateStep

Chooses the cards the recommendations are drawn from.

FieldTypeRequiredNullableNotes
sourceenumYesNoWhere the candidates come from: all, color_identity, explicit, or set. See the table below.
parametersstring[]NoYesInput to the source; what it means depends on the source. At most 1,000 items, each at most 150 characters.
SourceParametersCandidates
allNot used.Every card, whatever its color identity.
color_identityOptional. The first item is a color identity written as color letters, such as “WUB”. An empty string means colorless.Every card that fits within that color identity. Without parameters, the commanders’ color identity, which is also what an omitted candidate_step ranks.
explicitRequired. Card identifiers in the request’s card_format.The listed cards. Identifiers that don’t match a card are skipped.
setRequired. The first item is a Scryfall set code, such as “fdn”.Every card with a printing in that set that fits the commanders’ color identity. A set code that doesn’t exist is rejected with error_invalid_request.

CardRecommendationSlim

A recommendation entry in the response.

FieldTypeRequiredNullableNotes
oracle_iduuidYesNoUUID for the recommended card.
namestringYesNoHuman-readable card name.
scoredoubleYesNoRecommendation score used to rank results.

ApiResult<RecommendResultTop>

The standard response envelope wrapping the list of recommendations.

FieldTypeRequiredNullableNotes
result_codeenumYesNoShared status enum describing success or failure.
dataRecommendResultTopNoYesOn success, an object whose recommendations array holds up to 200 CardRecommendationSlim entries, highest score first.
errorobjectNoYesContains a messages array on failure.

ApiResultCode

The values of result_code this endpoint returns, and the HTTP status each one comes with.

CodeHTTPMeaning
success200The request worked, and data holds the recommendations.
error_invalid_request400The body is malformed, breaks one of the limits above, or names a set that doesn’t exist. error.messages says what to fix.
error_invalid_cards400The commander or partner doesn’t match a card in the chosen card_format. Newly revealed cards can take a while to be recognized. Deck cards that don’t match are skipped instead.
error_rate_limited429Too many requests. Wait before sending more; see Rate Limits.
error_booting503The service is starting up. Retry after the number of seconds in the Retry-After header.
error_model_loading503A new model is being loaded. Retry after the number of seconds in the Retry-After header.
error_unknown500Something failed on our side. Try again later.

Other parts of the API share this enum, so it has five more values. The recommendations endpoint never returns them:

  • error_unauthorized 401
  • error_not_found 404
  • error_invalid_deck 400
  • error_invalid_backend 400
  • error_backend_downstream 502

Request Body

Example

{
  "card_format": "name",
  "commander": "Gabriel Angelfire",
  "partner": null,
  "deck": [
    "Arbor Elf",
    "Beast Within",
    "Cultivate",
    "Danitha Capashen, Paragon",
    "Eidolon of Blossoms",
    "Heliod's Pilgrim",
    "Jukai Naturalist",
    "Kor Spiritdancer",
    "Mesa Enchantress",
    "Sanctum Weaver",
    "Sythis, Harvest's Hand",
    "Utopia Sprawl"
  ]
}

With weights and a candidate set

The same deck, leaning harder on its enchantress cards and away from land ramp, with recommendations drawn only from Foundations cards in the commander’s colors.

{
  "card_format": "name",
  "commander": "Gabriel Angelfire",
  "partner": null,
  "deck": [
    "Arbor Elf",
    "Beast Within",
    "Cultivate",
    "Danitha Capashen, Paragon",
    "Eidolon of Blossoms",
    "Heliod's Pilgrim",
    "Jukai Naturalist",
    "Kor Spiritdancer",
    "Mesa Enchantress",
    "Sanctum Weaver",
    "Sythis, Harvest's Hand",
    "Utopia Sprawl"
  ],
  "weighted_deck": {
    "Sythis, Harvest's Hand": 3,
    "Mesa Enchantress": 2,
    "Cultivate": -1
  },
  "candidate_step": {
    "source": "set",
    "parameters": [
      "fdn"
    ]
  }
}

Response

Success Example

{
  "result_code": "success",
  "data": {
    "recommendations": [
      {
        "oracle_id": "795b096a-2bce-4588-a2c9-abc5ea40dc0c",
        "name": "Enchantress's Presence",
        "score": 0.9998
      },
      {
        "oracle_id": "dcb7e046-f01b-497c-88e5-57794eb30ce5",
        "name": "Canopy Vista",
        "score": 0.9998
      },
      {
        "oracle_id": "c8b143ad-43ec-4e0d-a440-e348daa31391",
        "name": "Swiftfoot Boots",
        "score": 0.9997
      },
      {
        "oracle_id": "e521322b-0e83-458c-8936-7021a80ee279",
        "name": "Temple of Plenty",
        "score": 0.9997
      },
      {
        "oracle_id": "24882fa2-3fe9-4c1b-aa3d-0e6488b9db27",
        "name": "Heroic Intervention",
        "score": 0.9994
      },
      {
        "oracle_id": "48a99dce-0aa9-4aac-81df-cec5f94c639d",
        "name": "Archon of Sun's Grace",
        "score": 0.9991
      }
    ]
  },
  "error": null
}

cURL

Example request against the public-release API:

curl -X POST https://api.recommander.cards/public-release/api/decks/recommend/top \
  -H "Content-Type: application/json" \
  --data-binary @- <<'EOF'
{
  "card_format": "name",
  "commander": "Gabriel Angelfire",
  "partner": null,
  "deck": [
    "Arbor Elf",
    "Beast Within",
    "Cultivate",
    "Danitha Capashen, Paragon",
    "Eidolon of Blossoms",
    "Heliod's Pilgrim",
    "Jukai Naturalist",
    "Kor Spiritdancer",
    "Mesa Enchantress",
    "Sanctum Weaver",
    "Sythis, Harvest's Hand",
    "Utopia Sprawl"
  ]
}
EOF

Notes

Note that only cards with a score above 0.7 are included in the recommendations. If you do not receive any recommendations, it may be because the model did not find any cards that met that threshold for your query. You can experiment with different commanders, partners, and deck contents to see how the recommendations change.

A request that is malformed or breaks one of the limits above is answered with HTTP 400 and a result_code of error_invalid_request. Its error.messages array has one entry for each problem found.