POST /ideabank/proposals

Submit a new proposal to an idea bank on behalf of a panelist. Requires the canSubmitProposal capability (see Get Idea Bank). When the idea bank collects contact info, the panelist’s contact details can be attached to the submission.

Request

POST /public/ideabank/proposals

Headers

HeaderRequiredDescription
AuthorizationYesCompound idea-bank token from Tenant API
Content-TypeYesapplication/json

Request Body

FieldTypeRequiredDescription
titlestringYesProposal title
descriptionstringYesProposal description
contactInfostringNoPanelist contact value (e.g. email), stored when the idea bank collects it
contactInfoLabelstringNoLabel identifying the kind of contact info (matches contactInfoCollection.label)
{
	"title": "Dark mode",
	"description": "Please add a dark theme for night-time use.",
	"contactInfo": "panelist@example.com",
	"contactInfoLabel": "email"
}

contactInfo is only stored when both contactInfo and contactInfoLabel are supplied. Use the contactInfoCollection object from the Get Idea Bank response to decide whether to collect and which label to send.

Response

{
	"proposalId": "p-abc123",
	"title": "Dark mode",
	"description": "Please add a dark theme for night-time use.",
	"votes": 0,
	"totalVotes": 0
}

Response Fields

FieldTypeDescription
proposalIdstringUnique identifier of the created proposal
titlestringProposal title as stored
descriptionstringProposal description as stored
votesintegerNet vote score (0 for a new proposal)
totalVotesintegerTotal number of votes cast (0 for a new proposal)

Examples

cURL

curl -X POST \
  "https://api.votito.com/public/ideabank/proposals" \
  -H "Authorization: abc123:xyz789:ses456" \
  -H "Content-Type: application/json" \
  -d '{"title":"Dark mode","description":"Please add a dark theme."}'

JavaScript

const submitProposal = async (publicKey, { title, description, contactInfo, contactInfoLabel } = {}) => {
	const response = await fetch('https://api.votito.com/public/ideabank/proposals', {
		method: 'POST',
		headers: {
			'Authorization': publicKey,
			'Content-Type': 'application/json'
		},
		body: JSON.stringify({ title, description, contactInfo, contactInfoLabel })
	});

	if (!response.ok) {
		throw new Error(`Failed to submit proposal: ${response.status}`);
	}

	return response.json();
};

// Usage
const proposal = await submitProposal(publicKey, {
	title: 'Dark mode',
	description: 'Please add a dark theme.'
});
console.log(`Created proposal ${proposal.proposalId}`);

Python

import requests

def submit_proposal(public_key, title, description, contact_info=None, contact_info_label=None):
    body = {"title": title, "description": description}
    if contact_info and contact_info_label:
        body["contactInfo"] = contact_info
        body["contactInfoLabel"] = contact_info_label
    response = requests.post(
        "https://api.votito.com/public/ideabank/proposals",
        headers={
            "Authorization": public_key,
            "Content-Type": "application/json"
        },
        json=body
    )
    response.raise_for_status()
    return response.json()

# Usage
proposal = submit_proposal(public_key, "Dark mode", "Please add a dark theme.")
print(proposal["proposalId"])

Error Handling

StatusErrorDescription
400field-requiredtitle or description is missing. details.field names the missing field.
401UnauthorizedMissing or invalid token
403ForbiddenToken expired, or the panelist cannot submit proposals
429resource-busyServer is busy. Retry after a short delay.

Notes