Getting Started

Welcome to the Uplup API documentation. Get up and running with our powerful APIs in minutes.

Base URL: https://api.uplup.com

Quick Start Guide

  1. Sign up for an Uplup account (Free plan includes read-only API access)
  2. Generate your API keys from the dashboard
  3. Include your API key in the Authorization header
  4. Make your first API request

Prerequisites

  • An Uplup account (any plan — Free includes read-only access)
  • API keys (generate from your dashboard)
  • HTTPS support for secure API calls

Authentication

Secure your API requests with Bearer token authentication using your Uplup API keys.

API Key Format

API Key Structure

All Uplup API keys follow the format: uplup_[env]_[32_characters]

LIVEuplup_live_abc123def456...

Production environment - Use for live applications

TESTuplup_test_xyz789abc123...

Development environment - Use for testing and development

Security Best Practices

Never expose API keys in client-side code

Always make API calls from your backend server. API keys should never be visible in browser code, mobile apps, or public repositories.

Do This

  • • Store API keys in environment variables
  • • Use HTTPS for all API requests
  • • Implement proper error handling
  • • Rotate keys regularly
  • • Use test keys for development

Avoid This

  • • Hardcoding keys in source code
  • • Committing keys to version control
  • • Sharing keys via email or chat
  • • Using live keys in development
  • • Making requests from frontend

Rate Limiting

Limits by Plan

Free
  • • Read-only access
  • • 2/sec · 60/min · 1,000/hr
  • • 1 API key
Starter
  • • Read + Write
  • • 5/sec · 150/min · 5,000/hr
  • • 2 API keys
Pro
  • • Full access
  • • 10/sec · 300/min · 10,000/hr
  • • 5 API keys
Business
  • • Full + Webhooks
  • • 10/sec · 600/min · 25,000/hr
  • • 10 API keys
Scale
  • • Full + Webhooks
  • • 10/sec · 1,000/min · 50,000/hr
  • • Unlimited API keys

Enterprise: Need higher limits? for custom rate limits and dedicated infrastructure.

Forms & Quizzes API

Full REST API for forms, quizzes, fields, submissions, analytics, design, webhooks, and account management. 33 endpoints with Bearer token authentication, scope-based access control, and rate limiting.

Base URL: https://api.uplup.com/api/v1/forms

Forms
CRUD, Clone, Publish
Submissions
List, Export CSV
Quiz
Results, Leaderboard
Webhooks
7 Event Types

Wheel Picker API

Create, manage, and interact with spinning wheels programmatically. 23 endpoints for building decision-making tools, games, giveaways, and interactive experiences.

Base URL: https://api.uplup.com/api/v1/wheels

Wheels
CRUD, Clone, Archive
Entries
Add, Update, Remove
Spins
Record, History, Stats
Share
Embed, Public Links

Core Endpoints

GET/api/v1/wheels- List all wheels
POST/api/v1/wheels- Create a new wheel
GET/api/v1/wheels/{id}- Get wheel details
PUT/api/v1/wheels/{id}- Update a wheel
DELETE/api/v1/wheels/{id}- Delete a wheel

Entries & Spins

GET/api/v1/wheels/{id}/entries- List entries
POST/api/v1/wheels/{id}/entries- Add entries
PUT/api/v1/wheels/{id}/entries- Replace all entries
DELETE/api/v1/wheels/{id}/entries- Remove entries by index or name
POST/api/v1/wheels/{id}/spin- Record a spin result

Settings, Appearance & Analytics

GET/api/v1/wheels/{id}/settings- Get wheel settings
PUT/api/v1/wheels/{id}/settings- Update settings
PUT/api/v1/wheels/{id}/appearance- Update colors, fonts, needle
GET/api/v1/wheels/{id}/stats- Spin analytics
GET/api/v1/wheels/{id}/results- Winner history
GET/api/v1/wheels/{id}/history- Full audit log

Share, Embed & Lifecycle

GET/api/v1/wheels/{id}/share- Get share settings
PUT/api/v1/wheels/{id}/share- Enable/disable public sharing
GET/api/v1/wheels/{id}/embed- Get embed code
POST/api/v1/wheels/{id}/clone- Duplicate a wheel
POST/api/v1/wheels/{id}/archive- Archive a wheel
POST/api/v1/wheels/{id}/restore- Restore archived wheel
GET/api/v1/wheels/{id}/background- Get/set/remove background
Uplup

Welcome to Uplup API

Build powerful applications with our comprehensive REST API. Create interactive wheels, manage entries, track analytics, and more with simple HTTP requests.

Quick Start

1

Get API Keys

Sign up for any plan (including Free) and generate your API key from the dashboard.

Generate keys
2

Make Requests

Use your API key to authenticate requests to our REST endpoints.

Learn authentication →
3

Build & Ship

Create wheels, manage entries, and integrate our tools into your applications.

Explore endpoints →

Try it out

List your wheels - JavaScript
// Bearer Token Authentication
const apiKey = 'uplup_live_your_api_key_here';

const response = await fetch(
  'https://api.uplup.com/api/v1/wheels',
  {
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    }
  }
);

const data = await response.json();
console.log('Your wheels:', data);

What you can build

Interactive Decision Wheels

Create customizable spinning wheels for games, random selection, and decision-making tools.

Entry Management

Dynamically add, remove, and modify wheel entries through API calls or CSV imports.

Real-time Results

Get instant results from wheel spins with detailed analytics and winner tracking.

Webhook Integration

Receive real-time notifications when wheels are spun, winners are selected, or entries change.

Embeddable Widgets

Embed interactive wheels directly into your website or application with our embed API.

Analytics & Insights

Track usage patterns, popular entries, and engagement metrics to optimize your wheels.

API Information

Base URL

https://api.uplup.com

API Version

v1.0 - StableREST API with JSON

Authentication

Authenticate your API requests using Bearer token authentication with your Uplup API key.

API Credentials

Bearer Token Authentication

Every API request requires your API key sent as a Bearer token:

  • API Key: Secret token following the format uplup_[env]_[32_characters]
  • Send via the Authorization: Bearer YOUR_API_KEY header

Your API key is shown only once when created. Store it securely — it cannot be retrieved later.

LIVEuplup_live_abc123def456...

Production environment - Use for live applications

TESTuplup_test_xyz789abc123...

Development environment - Use for testing and development

Authentication Methods

Use Bearer token authentication by including your API key in the Authorization header of every request.

Authentication Examples - JavaScript
// Bearer Token Authentication (Recommended)
const apiKey = 'uplup_live_abc123def456789...';

// Using fetch with Bearer token
const response = await fetch(
  'https://api.uplup.com/api/v1/forms/forms',
  {
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    }
  }
);

const data = await response.json();

// Using axios with Bearer token
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.uplup.com',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  }
});

// Forms & Quizzes API
const forms = await api.get('/api/v1/forms/forms');

// Wheel Picker API (also accepts Bearer token)
const wheels = await api.get('/api/wheel/wheels');

Security Best Practices

Never expose API keys in client-side code

Always make API calls from your backend server. API keys should never be visible in browser code, mobile apps, or public repositories.

Do This

  • • Store API keys in environment variables
  • • Use HTTPS for all API requests
  • • Implement proper error handling
  • • Rotate keys regularly
  • • Use test keys for development

Avoid This

  • • Hardcoding keys in source code
  • • Committing keys to version control
  • • Sharing keys via email or chat
  • • Using live keys in development
  • • Making requests from frontend

Error Handling

The Uplup API uses conventional HTTP status codes and returns structured JSON error responses. Every error includes a type, human-readable message, and machine-readable code for programmatic handling.

Error Response Format

All errors follow a consistent structure. The param field is included when the error relates to a specific request parameter.

{
  "error": {
    "type": "invalid_request_error",
    "message": "Parameter 'title' cannot be empty.",
    "status": 400,
    "code": "validation_error",
    "param": "title"
  }
}
FieldTypeDescription
typestringError category. One of: authentication_error, permission_error, invalid_request_error, rate_limit_error, api_error
messagestringHuman-readable description of the error
statusintegerHTTP status code (matches the response status)
codestringMachine-readable error code for programmatic handling
paramstring?The parameter that caused the error (included when applicable)

Error Types

authentication_error401

The API key is missing, malformed, inactive, or expired.

permission_error403

The API key is valid but lacks the required scope, or the request is blocked by IP/origin restrictions.

invalid_request_error400, 404, 405, 413, 415

The request is invalid — wrong parameters, missing fields, unknown resource, or unsupported method.

rate_limit_error429

Too many requests. Check the Retry-After header and back off.

api_error500

Something went wrong on our end. These are rare and automatically logged.

HTTP Status Codes

2xx — Success
200
OK — Request succeeded. Response body contains the requested data.
4xx — Client Error
400
Bad RequestThe request body is invalid, a required parameter is missing, or a parameter value is out of range.
401
UnauthorizedNo API key provided, the key format is invalid, or the key is inactive/expired.
403
ForbiddenThe API key is valid but does not have the required scope, or the request IP/origin is blocked.
404
Not FoundThe requested resource does not exist or does not belong to your brand.
405
Method Not AllowedThe HTTP method is not supported for this endpoint. Check the Allow response header.
413
Payload Too LargeThe request body exceeds the 1 MB size limit.
415
Unsupported Media TypeContent-Type must be application/json for POST, PATCH, and PUT requests.
429
Too Many RequestsRate limit exceeded. Check the Retry-After header for when to retry.
5xx — Server Error
500
Internal Server Error — An unexpected error occurred. If this persists, .

Error Code Reference

Use the code field for programmatic error handling. The message field provides human-readable context but may change — do not match on it.

401Authentication Errors

CodeMessageCause
invalid_api_keyMissing API key. Include your key in the Authorization header: Bearer uplup_live_xxxNo Authorization: Bearer ... header
invalid_api_keyInvalid API key format. Expected: uplup_live_[32 hex chars] or uplup_test_[32 hex chars].Key does not match required format
invalid_api_keyInvalid API key. Check that your key is correct and active.Key not found, deactivated, or expired

403Permission Errors

CodeMessageCause
plan_scope_restrictedThe '{scope}' scope requires the {Plan} plan or higher.Your plan does not include this scope. Upgrade to unlock it.
missing_scopeThis API key does not have the '{scope}' scope.The key was created with Read Only permissions but a write scope is required. Recreate the key with Read & Write.
ip_not_allowedRequest IP address is not in the allowed list for this API key.The key has an IP allowlist configured and your IP is not on it.
origin_not_allowedRequest origin is not in the allowed list for this API key.The key has an origin allowlist and the request Origin header does not match.
webhook_limit_reachedWebhook limit reached. Your plan allows {N} active webhooks.Maximum active webhooks for your plan. Delete unused webhooks or upgrade.

400Validation Errors

CodeExample MessageCause
validation_errorMissing required parameter 'title'.A required field is missing from the request body.
validation_errorParameter 'title' cannot be empty.A required string field is present but empty.
validation_errorParameter 'title' exceeds maximum length of 500 characters.A string field exceeds its maximum length.
validation_errorParameter 'presentation_mode' must be one of: traditional, conversational.An enum field has an invalid value.
validation_errorParameter 'position' must be an integer.A numeric field received a non-numeric value.
validation_errorParameter 'required' must be a boolean.A boolean field received a non-boolean value.
validation_errorParameter 'fields' must be an array.An array field received a non-array value.
validation_errorInvalid form_id format. Must be exactly 8 alphanumeric characters.The form ID in the URL path is malformed.
validation_errorMaximum 200 fields allowed per form.The fields array exceeds the per-form field limit.
validation_errorRequest body cannot be empty for PATCH.A PATCH request was sent with no body.
validation_errorNo valid fields to update.The request body has no recognized fields for this endpoint.
validation_errorParameter 'url' must use HTTPS for webhook URLs.Webhook URLs must use HTTPS, not HTTP.
validation_errorParameter 'url' cannot point to localhost or loopback addresses.Webhook URLs cannot target internal/private addresses (SSRF protection).

404Not Found Errors

CodeExample MessageCause
resource_not_foundUnknown resource 'xyz'. Available resources: forms, wheels, themes, webhooks, account.The URL path does not match any API resource.
endpoint_not_foundUnknown sub-resource 'xyz'. Available: fields, submissions, analytics, quiz, design, clone, publish.The sub-path under /forms/{id}/ is not recognized.
form_not_foundNo form found with ID 'abc12345'.The form does not exist or belongs to a different brand.
field_not_foundNo field found with ID 'field-uuid'.The field ID does not exist in this form.
submission_not_foundNo submission found with ID 'sub-id'.The submission does not exist or has been deleted.
theme_not_foundNo theme found with ID '99'.The theme does not exist or is not accessible to your brand.
webhook_not_foundNo webhook found with ID '42'.The webhook does not exist or belongs to a different API key.

429Rate Limit Errors

CodeMessageRetry-After
rate_limit_exceededPer-second rate limit exceeded. Retry after 1 second.1
rate_limit_exceededPer-minute rate limit exceeded. Retry after 60 seconds.60
rate_limit_exceededHourly rate limit exceeded. Retry after N seconds.Seconds until hour resets
monthly_submission_limit_reachedMonthly submission limit reached. Your {Plan} plan allows {N} submissions per month.

OtherAdditional Error Codes

StatusCodeCause
405method_not_allowedHTTP method not supported. Check the Allow response header for valid methods.
413body_too_largeRequest body exceeds 1 MB. Reduce the payload size.
415unsupported_content_typeSet Content-Type: application/json on POST/PATCH requests.
500internal_errorServer error. Safe to retry with exponential backoff. If persistent, contact support.

Example Error Responses

Missing API key:

HTTP/1.1 401 Unauthorized

{
  "error": {
    "type": "authentication_error",
    "message": "Missing API key. Include your key in the Authorization header: Bearer uplup_live_xxx",
    "status": 401,
    "code": "invalid_api_key"
  }
}

Read-only key attempting a write operation:

HTTP/1.1 403 Forbidden

{
  "error": {
    "type": "permission_error",
    "message": "This API key does not have the 'forms:write' scope. Update key permissions in your dashboard.",
    "status": 403,
    "code": "missing_scope"
  }
}

Invalid parameter:

HTTP/1.1 400 Bad Request

{
  "error": {
    "type": "invalid_request_error",
    "message": "Parameter 'presentation_mode' must be one of: traditional, conversational.",
    "status": 400,
    "code": "validation_error",
    "param": "presentation_mode"
  }
}

Rate limit exceeded:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

{
  "error": {
    "type": "rate_limit_error",
    "message": "Per-minute rate limit exceeded. Retry after 60 seconds.",
    "status": 429,
    "code": "rate_limit_exceeded"
  }
}

Resource not found:

HTTP/1.1 404 Not Found

{
  "error": {
    "type": "invalid_request_error",
    "message": "No form found with ID 'abc12345'.",
    "status": 404,
    "code": "form_not_found",
    "param": "form_id"
  }
}

Best Practices

  • 1.Switch on code, not message — Error codes are stable. Messages may be refined over time.
  • 2.Respect Retry-After — On 429 errors, wait the specified seconds before retrying. Do not retry immediately.
  • 3.Use exponential backoff for 5xx errors — Start at 1s, double each attempt, cap at 30s. These are transient.
  • 4.Check param for validation errors — It tells you exactly which field needs fixing.
  • 5.Log the X-Request-Id header — Include it when contacting support. It uniquely identifies each API request.
Error Handling Example - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms', {
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  }
});

if (!response.ok) {
  const error = await response.json();

  switch (error.error?.code) {
    case 'invalid_api_key':
      console.error('Check your API key');
      break;
    case 'missing_scope':
      console.error('Key lacks required permissions');
      break;
    case 'rate_limit_exceeded':
      const retryAfter = response.headers.get('Retry-After');
      console.error(`Rate limited. Retry in ${retryAfter}s`);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      break;
    case 'validation_error':
      console.error(`Invalid param: ${error.error.param}`);
      break;
    default:
      console.error(error.error?.message);
  }
}

API access is available on all plans, including Free. Free plan includes read-only access (1,000 req/hr). Write access requires the Starter plan or higher. Webhooks require the Business plan or higher.

Rate Limiting

Limits by Plan

Rate limits are enforced per API key across three windows: per-second (burst), per-minute (short-term), and per-hour (budget). Exceeding any limit returns a 429 error with a Retry-After header indicating which window was exceeded.

PlanAccess/Second/Minute/HourAPI Keys
FreeRead Only2601,0001
StarterFull Access51505,0002
ProFull Access1030010,0005
BusinessFull Access + Webhooks1060025,00010
ScaleFull Access + Webhooks101,00050,000Unlimited
EnterpriseNeed higher limits? for custom rate limits.

Maximum burst rate is 10 requests/second across all plans. Higher plans differ in sustained throughput.

Submission Limits

Submissions count against your monthly limit regardless of source — public form, embed, or API. When your limit is reached, submission endpoints return a 429 error. Read endpoints continue to work normally.

PlanMonthly Submissions
Free100
Starter250
Pro1,000
Business5,000
Scale25,000+

Submission Limit Error Response

{
  "error": {
    "type": "rate_limit_error",
    "message": "Monthly submission limit reached. Your Free plan allows 100 submissions per month.",
    "status": 429,
    "code": "monthly_submission_limit_reached",
    "details": {
      "limit": 100,
      "used": 100,
      "resets_at": "2026-04-01T00:00:00Z"
    }
  }
}

Scope Access by Plan

Each plan tier determines which API scopes are available. Attempting to use a scope not included in your plan returns a 403 error.

ScopeFreeStarterProBusinessScale
forms:read
forms:write
submissions:read
submissions:write
analytics:read
quiz:read
quiz:write
themes:read
webhooks:read
webhooks:write
account:read
wheels:read
wheels:write

Forms & Quizzes API

Full CRUD for forms, quizzes, fields, submissions, analytics, design, webhooks, and account management. All endpoints use Bearer token authentication and return Stripe-style JSON responses.

Base URL

https://api.uplup.com/api/v1/forms

Authentication

All requests require a Bearer token: Authorization: Bearer uplup_live_xxx

API access is available on all plans (Free includes read-only). Manage keys in your dashboard.

33
Endpoints
15
Scopes
6
Languages
v1
Version

Forms

Scope: forms:read / forms:write

GET

List Forms

/forms

Returns a paginated list of all forms and quizzes in your account.

GET List Forms - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms?type=quiz&limit=10', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Create Form

/forms

Create a new form or quiz with optional fields, styling, and quiz settings.

POST Create Form - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'title': 'Customer Feedback',
    'content_type': 'form',
    'fields': [
      {
        'type': 'Short Text',
        'title': 'Your name'
      },
      {
        'type': 'Multiple Choice',
        'title': 'How did you hear about us?',
        'options': [
          'Google',
          'Social Media',
          'Friend'
        ]
      }
    ]
  })
});

const data = await response.json();
console.log(data);
GET

Get Form

/forms/{form_id}

Retrieve a single form with all its fields, pages, styling, and settings.

GET Get Form - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
PATCH

Update Form

/forms/{form_id}

Update form properties. Only provided fields are modified.

PATCH Update Form - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'title': 'Updated Title',
    'description': 'New description'
  })
});

const data = await response.json();
console.log(data);
DELETE

Delete Form

/forms/{form_id}

Permanently delete a form and all associated data.

This action is permanent and cannot be undone.
DELETE Delete Form - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Clone Form

/forms/{form_id}/clone

Create a duplicate of an existing form with all fields, styling, and settings.

POST Clone Form - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/clone', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Publish / Unpublish

/forms/{form_id}/publish

Toggle the published status of a form. Published forms are accessible via their public URL.

POST Publish / Unpublish - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/publish', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'action': 'publish'
  })
});

const data = await response.json();
console.log(data);

Fields

Manage individual form fields. Scope: forms:read / forms:write

GET

List Fields

/forms/{form_id}/fields

Get all fields for a form, ordered by position.

GET List Fields - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/fields', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Add Field

/forms/{form_id}/fields

Add a new field to the form at an optional position.

POST Add Field - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/fields', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'type': 'Multiple Choice',
    'title': 'What is your favorite color?',
    'options': [
      'Red',
      'Blue',
      'Green'
    ],
    'required': true,
    'position': 2
  })
});

const data = await response.json();
console.log(data);
GET

Get Field

/forms/{form_id}/fields/{field_id}

Retrieve a single field by ID.

GET Get Field - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/fields/f_a1b2c3', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
PATCH

Update Field

/forms/{form_id}/fields/{field_id}

Update field properties. Only provided fields are modified.

PATCH Update Field - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/fields/f_a1b2c3', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'title': 'Full name',
    'required': true
  })
});

const data = await response.json();
console.log(data);
DELETE

Delete Field

/forms/{form_id}/fields/{field_id}

Remove a field from the form.

DELETE Delete Field - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/fields/f_a1b2c3', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Reorder Fields

/forms/{form_id}/fields/reorder

Set the order of all fields by providing field IDs in the desired sequence.

POST Reorder Fields - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/fields/reorder', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'field_ids': [
      'f_d4e5f6',
      'f_a1b2c3',
      'f_g7h8i9'
    ]
  })
});

const data = await response.json();
console.log(data);

Submissions

Scope: submissions:read / submissions:write

GET

List Submissions

/forms/{form_id}/submissions

Get paginated submissions for a form with optional filtering.

GET List Submissions - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/submissions?limit=10&since=2024-01-01', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
GET

Get Submission

/forms/{form_id}/submissions/{submission_id}

Retrieve a single submission with all decrypted values.

GET Get Submission - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/submissions/sub_123abc', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
DELETE

Delete Submission

/forms/{form_id}/submissions/{submission_id}

Soft-delete a submission (can be recovered).

DELETE Delete Submission - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/submissions/sub_123abc', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Export Submissions (CSV)

/forms/{form_id}/submissions/export

Export all submissions as a CSV file. Returns raw CSV data.

The response Content-Type will be text/csv with a Content-Disposition header for file download.
POST Export Submissions (CSV) - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/submissions/export', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'format': 'csv'
  })
});

const data = await response.json();
console.log(data);

Analytics

Scope: analytics:read

GET

Analytics Overview

/forms/{form_id}/analytics/overview

Get high-level analytics: total submissions, views, conversion rate, and recent activity.

GET Analytics Overview - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/analytics/overview', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
GET

Submission Trends

/forms/{form_id}/analytics/submissions

Time-series submission data, grouped by day, week, or month.

GET Submission Trends - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/analytics/submissions?group_by=week', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
GET

Geography Breakdown

/forms/{form_id}/analytics/geography

Submission counts by country/region.

GET Geography Breakdown - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/analytics/geography', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
GET

Performance Metrics

/forms/{form_id}/analytics/performance

Hourly activity patterns, daily trends, and completion time statistics.

GET Performance Metrics - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/analytics/performance', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);

Quiz

Quiz-specific endpoints for scoring, results, and leaderboards. Scope: quiz:read / quiz:write

GET

Get Quiz Settings

/forms/{form_id}/quiz/settings

Retrieve quiz configuration: scoring mode, timing, behavior, results display, retakes, and lead capture.

GET Get Quiz Settings - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/quiz/settings', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
PATCH

Update Quiz Settings

/forms/{form_id}/quiz/settings

Merge new settings into existing quiz configuration (deep merge).

PATCH Update Quiz Settings - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/quiz/settings', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'timing': {
      'enabled': true,
      'time_limit': 600
    },
    'results': {
      'show_correct_answers': true
    }
  })
});

const data = await response.json();
console.log(data);
GET

Quiz Results

/forms/{form_id}/quiz/results

Get scored quiz submissions with points, percentage, and pass/fail status.

GET Quiz Results - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/quiz/results?limit=10', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
GET

Leaderboard

/forms/{form_id}/quiz/leaderboard

Top scorers ranked by percentage (descending), then by submission time (ascending).

GET Leaderboard - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/quiz/leaderboard?limit=5', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);

Design & Themes

Scope: forms:read / forms:write and themes:read

GET

Get Design

/forms/{form_id}/design

Retrieve the form's styling, background, logo, and presentation settings.

GET Get Design - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/design', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
PATCH

Update Design

/forms/{form_id}/design

Update the form's visual styling.

PATCH Update Design - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/design', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'styling': {
      'primaryColor': '#E53E3E',
      'fontFamily': 'Poppins'
    }
  })
});

const data = await response.json();
console.log(data);
POST

Apply Theme

/forms/{form_id}/design/theme

Apply a preset or custom theme to the form.

POST Apply Theme - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/forms/abc12345/design/theme', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'theme_id': 'modern-dark'
  })
});

const data = await response.json();
console.log(data);
GET

List Themes

/themes

Get all available themes (presets and custom).

GET List Themes - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/themes', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
GET

Get Theme

/themes/{theme_id}

Retrieve a single theme's details and styling data.

GET Get Theme - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/themes/modern-dark', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);

Webhooks

Subscribe to real-time event notifications via HTTP POST. Requires Business plan or higher. Scope: webhooks:read / webhooks:write

Event Types (19)

Form Lifecycle
form.created

New form or quiz created

form.updated

Form settings modified

form.deleted

Form deleted

form.published

Form published (live)

form.unpublished

Form taken offline

form.cloned

Form duplicated

Submissions
submission.created

New response received

submission.completed

Multi-step form completed

submission.deleted

Submission deleted

Quiz
quiz.completed

Quiz scored

quiz.passed

Passed with passing score

quiz.failed

Failed to reach passing score

quiz.timer_expired

Quiz timer ran out

Fields
field.created

Field added to form

field.updated

Field modified

field.deleted

Field removed

Responses
response.started

User began filling out form

response.page_completed

User completed a page with field data

response.abandoned

User left without completing

Payload Format

All webhook deliveries are sent as POST requests with a JSON body. Submission and quiz events include the full field responses:

{
  "event": "submission.created",
  "data": {
    "form_id": "abc12345",
    "submission_id": "sub_xyz789...",
    "content_type": "form",
    "fields": [
      { "id": "field-uuid-1", "type": "Short Text", "label": "Your Name", "value": "John Doe", "is_lead_capture": false },
      { "id": "field-uuid-2", "type": "Multiple Choice", "label": "Favorite Color", "value": "Blue", "is_lead_capture": false },
      { "id": "field-uuid-3", "type": "Checkboxes", "label": "Interests", "value": ["Sports", "Music"], "is_lead_capture": false },
      { "id": "lead_capture_email", "type": "Lead Capture Email", "label": "Email", "value": "john@example.com", "is_lead_capture": true }
    ],
    "metadata": {
      "country": "US",
      "region": "California"
    }
  },
  "timestamp": "2026-03-09T15:30:45+00:00"
}

Request Headers

HeaderDescription
Content-TypeAlways application/json
X-Uplup-SignatureHMAC-SHA256 hex digest of the raw payload using your webhook secret
X-Webhook-EventEvent type (e.g. submission.created)
X-Webhook-IDYour webhook subscription ID
User-AgentUplup-Webhook/1.0

Signature Verification

Verify webhook authenticity by computing the HMAC-SHA256 of the raw request body with your signing secret:

const crypto = require('crypto');

function verifySignature(payload, secret, signatureHeader) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf-8')
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}

Delivery Policy

  • Webhook deliveries time out after 5 seconds. Your endpoint should respond quickly.
  • Your endpoint must return a 2xx status code to be considered successful.
  • Failed deliveries are logged but not retried automatically. Check delivery logs in the dashboard.
  • All delivery attempts are recorded with status, response code, and timestamp.
  • Webhook URLs must use HTTPS. Private/internal IPs are blocked for security.
GET

List Webhooks

/webhooks

Get all webhook subscriptions for the current API key.

GET List Webhooks - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Create Webhook

/webhooks

Create a webhook endpoint. Subscribes to all 19 events by default, or specify a subset. Returns a signing secret (shown only once).

The signing secret is only returned on creation. Store it securely.
Webhooks require the Business plan or higher. Business = 10 webhook endpoints, Scale = 100.
POST Create Webhook - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'url': 'https://example.com/webhook',
    'events': [
      'submission.created',
      'submission.completed',
      'quiz.completed'
    ],
    'form_id': 'abc12345'
  })
});

const data = await response.json();
console.log(data);
GET

Get Webhook

/webhooks/{webhook_id}

Retrieve webhook details including recent delivery attempts.

GET Get Webhook - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks/wh_abc123', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
PATCH

Update Webhook

/webhooks/{webhook_id}

Modify webhook URL, subscribed events, or active status.

PATCH Update Webhook - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks/wh_abc123', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'is_active': false
  })
});

const data = await response.json();
console.log(data);
DELETE

Delete Webhook

/webhooks/{webhook_id}

Deactivate and remove a webhook subscription.

DELETE Delete Webhook - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks/wh_abc123', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Test Webhook

/webhooks/{webhook_id}/test

Send a test event to verify your webhook endpoint is receiving and processing events correctly.

POST Test Webhook - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks/wh_abc123/test', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
POST

Regenerate Secret

/webhooks/{webhook_id}/regenerate-secret

Generate a new signing secret for a webhook. The old secret is immediately invalidated. Store the new secret securely — it is only returned once.

The new secret is only shown once. Update your server immediately after regenerating.
POST Regenerate Secret - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks/wh_abc123/regenerate-secret', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
GET

Get Deliveries

/webhooks/{webhook_id}/deliveries

Retrieve delivery logs for a webhook. Includes event type, status, response code, and timestamps. Supports pagination.

GET Get Deliveries - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/webhooks/wh_abc123/deliveries?limit=10', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);

Account

Scope: account:read

GET

Get Account

/account

Retrieve account information, plan details, usage metrics, limits, and available features.

A limit value of -1 means unlimited.
GET Get Account - JavaScript
const response = await fetch('https://api.uplup.com/api/v1/forms/account', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);

Webhook Signature Verification

Every webhook delivery includes an X-Uplup-Signature header containing an HMAC-SHA256 signature of the request body using your webhook secret. Always verify this signature before processing events.

// Node.js signature verification
const crypto = require('crypto');

function verifyWebhookSignature(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-uplup-signature'];
  const isValid = verifyWebhookSignature(
    JSON.stringify(req.body),
    signature,
    process.env.WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the event
  const { event, data } = req.body;
  console.log('Received event:', event, data);
  res.json({ received: true });
});

Rate Limits

Rate limits are enforced per API key across three windows: per-second (burst protection), per-minute (short-term), and per-hour (budget). Exceeding any window returns a 429 error with a Retry-After header indicating which limit was hit.

PlanPer SecondPer MinutePer Hour
Free2601,000
Starter51505,000
Pro1030010,000
Business1060025,000
Scale101,00050,000
EnterpriseNeed higher limits?

The maximum burst rate is 10 requests per second across all plans. Higher plans differ in sustained throughput (per-minute and per-hour budgets).

Response Headers

  • X-RateLimit-Limit — Maximum requests per hour for your plan
  • X-RateLimit-Remaining — Remaining requests in the current hourly window
  • X-RateLimit-Reset — Unix timestamp when the hourly window resets
  • Retry-After — Seconds to wait before retrying (only on 429 responses)
  • X-Request-Id — Unique request ID for debugging

Wheel Picker API

Create, manage, and interact with spinning wheels programmatically. Build decision-making tools, games, and interactive experiences.

Base URL: https://api.uplup.com/api/wheel

Ready to get started?

Generate your API keys from the Uplup dashboard and start building amazing applications.

GET

List Wheels

/api/wheel/wheels

Retrieve a paginated list of all wheels belonging to your account.

GET List Wheels - JavaScript
// Get all wheels with pagination
const apiKey = 'YOUR_API_KEY';
const response =
await fetch('https://api.uplup.com/api/wheel/wheels', {
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  }
});

const data = await response.json();

if (response.ok) {
  // Success - API returns JSON response
  // Format: {"success": true, "data": {"wheels": [...]}}
  console.log('Response:', JSON.stringify(data, null, 2));
} else {
  // Handle error
  console.error('Error:', response.status);
  if (data.error) {
    console.error('Message:', data.error.message);
  }
}
POST

Create Wheel

/api/wheel/wheels

Create a new spinning wheel with customizable entries, settings, and appearance.

Entries can be simple strings or objects with additional metadata like weights or colors.
Maximum of 1000 entries per wheel. Large wheels may impact performance.
POST Create Wheel - JavaScript
// Create a new wheel
const wheelData = {
  wheel_name: "Team Lunch Picker",
  entries: ["Pizza Palace", "Burger Barn", "Taco Town", "Sushi Spot"],
  settings: {
    spinnerDuration: "normal",
    selectedColorSet: "Vibrant",
    colorSequence: ["#e6194b", "#3cb44b", "#ffe119", "#4363d8"],
    selectedAudio: "https://uplup-media.ams3.digitaloceanspaces.com/root/drum-roll-long.mp3",
    volume: 100,
    showTitle: true,
    removeAfterWin: false,
    winnersToSelect: 1
  }
};

const apiKey = 'YOUR_API_KEY';
const response = await fetch(
  'https://api.uplup.com/api/wheel/wheels', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(wheelData) // Follows redirects automatically
});

const result = await response.json();

if (response.ok) {
  // Success - API returns JSON response
  // Format: {"success": true, "data": {"wheel_id": "wheel_123", "message": "Wheel created successfully"}}
  console.log('Response:', JSON.stringify(result, null, 2));
} else {
  // Handle error
  console.error('Error:', response.status);
  if (result.error) {
    console.error('Message:', result.error.message);
  }
}
GET

Get Wheel

/api/wheel/wheels/{wheel_id}

Retrieve detailed information about a specific wheel including all entries and settings.

GET Get Wheel - JavaScript
// Get detailed wheel information
const apiKey = 'YOUR_API_KEY';
const wheelId = 'wheel_123';
const response = await fetch(
  `https://api.uplup.com/api/wheel/wheels/${wheelId}`, {
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  }
}) // Follows redirects automatically;

const wheel = await response.json();

if (response.ok) {
  // Success - API returns JSON response
  // Format: {"success": true, "data": {wheel details}}
  console.log('Response:', JSON.stringify(wheel, null, 2));
} else {
  // Handle error
  console.error('Error:', response.status);
  if (wheel.error) {
    console.error('Message:', wheel.error.message);
  }
}
POST

Spin Wheel (Coming Soon)

/api/wheel/wheels/{wheel_id}/spin

Programmatically spin a wheel and get the random result. Optionally save the result and trigger webhooks. Note: This endpoint is not yet implemented and will return a 501 error.

The random algorithm ensures fair distribution based on entry weights.
Spinning wheels with many entries may take longer to process.
POST Spin Wheel (Coming Soon) - JavaScript
// Spin a wheel and get the result
const apiKey = 'YOUR_API_KEY';
const wheelId = 'wheel_123';
const response = await fetch(
  `https://api.uplup.com/api/wheel/wheels/${wheelId}/spin`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    save_result: true,
    notify_webhooks: true
  }) // Follows redirects automatically
});

const result = await response.json();

if (response.ok) {
  // Success - API returns JSON response
  // Format: {"success": true, "data": {"winner": {...}, "results": [...]}}
  console.log('Response:', JSON.stringify(result, null, 2));
} else {
  // Handle error
  console.error('Error:', response.status);
  if (result.error) {
    console.error('Message:', result.error.message);
  }
}
PUT

Update Wheel

/api/wheel/wheels/{wheel_id}

Update an existing wheel's properties including title, entries, settings, and appearance.

PUT Update Wheel - JavaScript
// Update wheel name and add new entries
const updates = {
  wheel_name: "Updated Team Lunch Picker",
  entries: ["Pizza Palace", "Burger Barn", "Sushi Spot", "Deli Downtown"],
  settings: {
    spinnerDuration: "short",
    enableConfetti: false
  }
};

const apiKey = 'YOUR_API_KEY';
const wheelId = 'wheel_123';
const response = await fetch(
  `https://api.uplup.com/api/wheel/wheels/${wheelId}`, {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(updates) // Follows redirects automatically
});

const result = await response.json();

if (response.ok) {
  // Success - API returns JSON response
  // Format: {"success": true, "data": {"wheel_id": "wheel_123", "message": "Wheel created successfully"}}
  console.log('Response:', JSON.stringify(result, null, 2));
} else {
  // Handle error
  console.error('Error:', response.status);
  if (result.error) {
    console.error('Message:', result.error.message);
  }
}
DELETE

Delete Wheel

/api/wheel/wheels/{wheel_id}

Permanently delete a wheel and all its associated data including spin history.

This action is irreversible. All wheel data and history will be permanently deleted.
DELETE Delete Wheel - JavaScript
// Delete a wheel permanently
const apiKey = 'YOUR_API_KEY';
const wheelId = 'wheel_123';
const response = await fetch(
  `https://api.uplup.com/api/wheel/wheels/${wheelId}`, {
  method: 'DELETE',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  }
}) // Follows redirects automatically;

const result = await response.json();

if (response.ok) {
  // Success - API returns JSON response
  // Format: {"success": true, "message": "Wheel deleted successfully"}
  console.log('Response:', JSON.stringify(result, null, 2));
} else {
  // Handle error
  console.error('Error:', response.status);
  if (result.error) {
    console.error('Message:', result.error.message);
  }
}
POST

Manage Entries (Coming Soon)

/api/wheel/wheels/{wheel_id}/entries

Add, update, or remove entries from a wheel without replacing the entire entries array. Note: This endpoint is not yet implemented and will return a 501 error.

POST Manage Entries (Coming Soon) - JavaScript
// Add new entries to a wheel
const entryUpdate = {
  action: "add",
  entries: ["Mediterranean Cafe", "BBQ Joint", "Vegan Kitchen"]
};

const apiKey = 'YOUR_API_KEY';
const wheelId = 'wheel_123';
const response = await fetch(
  `https://api.uplup.com/api/wheel/wheels/${wheelId}/entries`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(entryUpdate) // Follows redirects automatically
});

const result = await response.json();

if (response.ok) {
  // Success - API returns JSON response
  // Format: {"success": true, "data": {"entries_added": 3, ...}}
  console.log('Response:', JSON.stringify(result, null, 2));
} else {
  // Handle error
  console.error('Error:', response.status);
  if (result.error) {
    console.error('Message:', result.error.message);
  }
}

// Remove specific entries
const removeUpdate = {
  action: "remove", 
  entries: ["entry_id_1", "entry_id_2"]
};