Skip to content
VoteFirst Docs
Dashboard

API

API quickstart

Read your board as JSON and cast your first vote through the API, in three steps. Every request below is one you can paste, as a curl command or in the language you would rather write.

If what you want is a working roadmap in one of your own pages, the embed script is less work and does more. The API is for building the interface yourself.

  1. Create an API key

    In the dashboard, under Share & Embed, press Create Key and give it a name you will recognise later. The key is shown in full once, so take it then.

    Keys need the PRO plan. On anything lower the key is made but every request is refused with not_allowed.

    In your terminal
    export VOTEFIRST_KEY="the key you just copied"

    The key is a secret. It opens every administrative route this project has, so call the API from a server you control. Do not put it in a web page, a single page application, or a mobile binary.

  2. Read the board

    Your project slug is the name in the address bar of your board. Send the key as X-API-Key on every request.

    curl "https://app.votefirst.app/api/v3/projects/your-project-slug" \
      -H "X-API-Key: $VOTEFIRST_KEY"
    
    curl "https://app.votefirst.app/api/v3/projects/your-project-slug/features?per_page=5" \
      -H "X-API-Key: $VOTEFIRST_KEY"
    const base = 'https://app.votefirst.app/api/v3/projects/your-project-slug';
    const headers = { 'X-API-Key': process.env.VOTEFIRST_KEY };
    
    const board = await fetch(base, { headers }).then(r => r.json());
    const features = await fetch(base + '/features?per_page=5', { headers }).then(r => r.json());
    import os, requests
    
    base = 'https://app.votefirst.app/api/v3/projects/your-project-slug'
    headers = {'X-API-Key': os.environ['VOTEFIRST_KEY']}
    
    board = requests.get(base, headers=headers).json()
    features = requests.get(base + '/features', headers=headers, params={'per_page': 5}).json()

    Every response carries the same three keys, so one decoder serves every route.

    Every response
    { "data": null, "meta": null, "error": null }

    A list fills meta with the page numbers. A failure fills error with a code you can branch on. Reads are anonymous: the key alone is enough.

  3. Mint an identity, then vote

    A write has to belong to somebody, so that the same somebody can withdraw it later. Mint a voter identity once and keep what comes back.

    Mint an identity
    curl -X POST "https://app.votefirst.app/api/v3/projects/your-project-slug/identity" \
      -H "X-API-Key: $VOTEFIRST_KEY"
    What comes back, with a 201
    {
      "data": {
        "voter_id": "anon_9f2c1a4e7b0d3856a2f19c4d6e8b0517",
        "kind": "anonymous",
        "anon_token": "9f2c1a4e7b0d3856a2f19c4d6e8b0517.Kf3xQ2mNpR7vT1sYbW9zAeUc",
        "display_name": "QuietOtter_4821",
        "banned": false,
        "voted_feature_ids": []
      },
      "meta": null,
      "error": null
    }

    Store anon_token and send it as X-VF-Anon on every later request. Reusing it is what keeps a visitor's votes and comments theirs. Presenting one you already hold answers 200 and renews it, so calling this route on every start costs one request and loses nothing.

    Vote for a feature
    curl -X POST "https://app.votefirst.app/api/v3/projects/your-project-slug/features/123/vote" \
      -H "X-API-Key: $VOTEFIRST_KEY" \
      -H "X-VF-Anon: $VOTEFIRST_ANON"

    Send the same request with -X DELETE to withdraw it. If you already sign your users in, send that token as X-VF-Token instead of minting anything, and the vote belongs to the real person.

Next