API v1
Log in
api / v1

Revup API reference

A JSON HTTP API for reading promotions, participants, contacts, and winners and for syncing audience data into your own systems. Account‑scoped, key‑authenticated, and predictable.

Base URL

Base https://revup.com/api/v1

All requests use HTTPS. JSON request and response bodies are expected throughout; application/json is the only supported content type.

Quickstart

Generate a key from Account › API, then pass it on every request via the x-api-key header.

Request
# List promotions for your account
curl https://revup.com/api/v1/promotions \
  -H "x-api-key: rvup_v1_your_key_here" \
  -H "accept: application/json"

Authentication

Every request must carry an API key in the x-api-key request header. Keys are account‑scoped: a key only ever returns data belonging to the account that created it.

Raw API keys are shown exactly once at creation. Revup stores only the hashed key plus a non‑secret prefix. Treat keys like passwords and revoke any that may have been exposed.

Header HTTP
x-api-key: rvup_v1_...
accept: application/json

Scopes & access

Each key includes scopes that define allowed access. Requests without the required scope fail with insufficient_scope.

ScopeAccess
promotions:readRead promotion metadata available to the account.
participants:readRead participant records and submission state.
participants:writeCreate or update participant records.
contacts:readRead contact and entry‑facing contact fields.
contacts:writeReserved for the coming contact write endpoint.
winners:readRead winner records and prize assignment details.

Promotion restrictions

Keys may be unrestricted, in which case they reach every promotion in the account, or limited to a specific subset. When a request targets a promotion the key cannot access, the API responds with promotion_restricted. Unknown promotion IDs, account mismatches, and key promotion restrictions intentionally share that code so inaccessible promotion existence is not leaked.

Response 403 insufficient_scope
{
  "success": false,
  "request_id": "2f4a8f2c0d4a6e9b7c1d2e3f",
  "error": {
    "code": "insufficient_scope",
    "message": "This API key does not include the required scope."
  }
}

Errors

Errors are JSON with a stable machine‑readable code and a human‑readable message. The HTTP status reflects the category.

StatusCodeMeaning
401missing_api_key
invalid_api_key
revoked_api_key
Missing, malformed, or revoked key.
403insufficient_scope
promotion_restricted
Key lacks the required scope, the promotion is outside the key's account, or the key is restricted away from that promotion.
429rate_limitedKey exceeded its per-minute request limit.
404not_foundThe requested API endpoint does not exist.
405method_not_allowedThe endpoint exists but does not support the HTTP method.
422validation_failedPath or query parameters failed validation.
Response Error envelope
{
  "success": false,
  "request_id": "2f4a8f2c0d4a6e9b7c1d2e3f",
  "error": {
    "code": "validation_failed",
    "message": "The 'limit' parameter must be between 1 and 250."
  }
}

Rate limits

Rate limits are enforced per API key. Default limits are 120 read requests per minute, 200 write requests per minute, and 60 heavy read requests per minute. Contact support if a production integration needs a higher key-specific limit.

ClassDefault limitApplies to
read120 / minuteDefault for GET, HEAD, and OPTIONS requests.
write200 / minuteDefault for write requests such as participant imports and bonus entries.
heavy_read60 / minuteReserved for expensive read endpoints.

Authenticated requests include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset after API key validation. Missing or invalid keys and pre-auth route/method errors do not include these headers. When a request is limited, the API returns HTTP 429 with Retry-After.

Response headers 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1747856460

Pagination

Collection endpoints return a cursor. Pass the returned next_cursor as the cursor query parameter to fetch the next page, and stop when has_more is false.

ParameterTypeNotes
limitintegerPage size. Endpoint-specific maximum.
cursorstringOpaque cursor returned from a prior response.
Response Paginated envelope
{
  "success": true,
  "request_id": "2f4a8f2c0d4a6e9b7c1d2e3f",
  "data": [ ... ],
  "pagination": {
    "next_cursor": "eyJpZCI6MTIzfQ",
    "has_more": true
  }
}

Retrieve account

Fetch the account available to the authenticated API key.

GET /account

Returns

FieldTypeNotes
idintegerAccount ID that owns the API key.
namestringAccount name.
websitestring/nullAccount website when present.
avatar_image_urlstring/nullAccount avatar or logo image URL when present.
created_at_epochinteger/nullUTC Unix timestamp from account creation metadata.
Request
curl https://revup.com/api/v1/account \
  -H "x-api-key: rvup_v1_your_key_here"
Response 200 OK
{
  "success": true,
  "request_id": "2f4a8f2c0d4a6e9b7c1d2e3f",
  "data": {
    "id": 2048,
    "name": "Acme Brewing Co.",
    "website": "https://acmebrewing.com",
    "avatar_image_url": "https://cdn.revup.com/.../acme.png",
    "created_at_epoch": 1716508800
  }
}

List promotions

List non-variant promotions visible to the authenticated API key account. Results are ordered by promotion ID and support cursor pagination.

GET /promotions promotions:read

Query parameters

ParameterTypeNotes
limitintegerPage size. Default 50.
cursorstringOpaque cursor from a prior response.

Returns

FieldTypeNotes
idintegerPromotion ID.
account_idintegerAccount ID that owns the promotion.
namestringPromotion name.
typestringInternal promotion type.
statusstringpending, live, or completed.
start_datestring/nullPromotion-local YYYY-MM-DD HH:MM:SS.
end_datestring/nullPromotion-local YYYY-MM-DD HH:MM:SS.
timezonestringIANA timezone for promotion-local timestamps.
default_languagestringPromotion default language code.
hosted_website_urlstringCustomer-configured hosted or installed URL when present.
form_fieldsarrayAPI/import-writable participant field IDs and human-readable titles for mapping. Option-backed fields include options. Custom fields use IDs such as ff_123; unsupported CAPTCHA, payment, signature, and file-upload fields are omitted.
Request
curl https://revup.com/api/v1/promotions?limit=50 \
  -H "x-api-key: rvup_v1_your_key_here"
Response 200 OK
{
  "success": true,
  "request_id": "a1b2c3d4e5f6",
  "data": [
    {
      "id": 123,
      "account_id": 2048,
      "name": "Summer Launch Giveaway",
      "type": "giveaway",
      "status": "live",
      "start_date": "2026-05-01 09:00:00",
      "end_date": "2026-06-15 23:59:59",
      "timezone": "America/Los_Angeles",
      "default_language": "en-us",
      "hosted_website_url": "https://acmebrewing.com/giveaway",
      "form_fields": [
        { "id": "email",      "title": "Email" },
        { "id": "first_name", "title": "First name" },
        { "id": "ff_456",     "title": "VIP tier",
          "options": ["Gold", "Silver", "Bronze"] }
      ]
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}

Retrieve a promotion

Fetch a single promotion by ID. Returns the same shape as a list item.

GET /promotions/{promotion_id} promotions:read

Path parameters

ParameterTypeNotes
promotion_idintegerPromotion ID. Must be accessible to the API key.
Request
curl https://revup.com/api/v1/promotions/123 \
  -H "x-api-key: rvup_v1_your_key_here"
Response 200 OK
{
  "success": true,
  "request_id": "a1b2c3d4e5f6",
  "data": {
    "id": 123,
    "account_id": 2048,
    "name": "Summer Launch Giveaway",
    "type": "giveaway",
    "status": "live",
    "start_date": "2026-05-01 09:00:00",
    "end_date": "2026-06-15 23:59:59",
    "timezone": "America/Los_Angeles",
    "default_language": "en-us",
    "hosted_website_url": "https://acmebrewing.com/giveaway",
    "form_fields": [ ... ]
  }
}

List participants

List participants for a single promotion. Default page size is 250. Promotion restrictions on the key are enforced. Add include_entry_data=true to include the raw bonus/entry ledger on each participant.

GET /promotions/{promotion_id}/participants participants:read

Query parameters

ParameterTypeNotes
limitintegerPage size. Default 250.
cursorstringOpaque cursor from a prior response.
include_entry_databooleanWhen true, includes the decoded entry ledger on each row.

Returns

FieldTypeNotes
idintegerParticipant/entrant ID.
promotion_idintegerPromotion ID this participant belongs to.
contact_idinteger/nullLinked account contact ID.
email, unique_id, first_name, middle_name, last_name, phonestring/nullCore identity fields.
address, address2, city, state, postal_code, countrystring/nullAddress fields when collected.
gender, birthdaystring/nullProfile fields when collected.
created_at, processed_atstring/nullPromotion-local YYYY-MM-DD HH:MM:SS timestamps.
created_at_epochinteger/nullUTC Unix timestamp for created_at.
statusstringInternal processing status, commonly pending or processed.
invalid, reporting_excluded, testbooleanParticipant validity/reporting/test flags.
payment_status, integration_statusstringPayment or integration state when applicable.
language_idinteger/nullSelected promotion language ID.
locationstring/nullStored location display value.
total_entries, total_referralsintegerCurrent entry and referral totals.
referring_participant_id, campaign_idinteger/nullReferral and tracking IDs when present.
entry_source_type, referring_source_url, entry_source_urlstring/nullCaptured source attribution fields.
device_typestringdesktop, mobile, or tablet.
avatar_urlstring/nullParticipant avatar URL when available.
ff_{promotion_form.id}string/array/nullCustom promotion field value at the top level using IDs from GET /promotions.
entry_dataobjectOnly present with include_entry_data=true. Raw decoded entry ledger keyed by block ID.
Request
curl https://revup.com/api/v1/promotions/123/participants?limit=250&include_entry_data=true \
  -H "x-api-key: rvup_v1_your_key_here"
Response 200 OK
{
  "success": true,
  "request_id": "a1b2c3d4e5f6",
  "data": [
    {
      "id": 98801,
      "promotion_id": 123,
      "contact_id": 55421,
      "email": "[email protected]",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "phone": null,
      "created_at": "2026-05-10 14:22:11",
      "created_at_epoch": 1747145731,
      "status": "processed",
      "total_entries": 12,
      "total_referrals": 3,
      "device_type": "desktop",
      "ff_456": "Gold"
    }
  ],
  "pagination": {
    "next_cursor": "eyJpZCI6OTg4MDF9",
    "has_more": true
  }
}

Retrieve a participant

Fetch a single participant by ID within a promotion. Returns the same shape as a list item.

GET /promotions/{promotion_id}/participants/{participant_id} participants:read

Path parameters

ParameterTypeNotes
promotion_idintegerPromotion ID.
participant_idintegerParticipant/entrant ID belonging to the promotion.
Request
curl https://revup.com/api/v1/promotions/123/participants/98801 \
  -H "x-api-key: rvup_v1_your_key_here"

Create participants

Create or import up to 50 participants per request. Existing participants are matched by normalized email, then phone, then unique_id and are skipped unless update_existing=true.

POST /promotions/{promotion_id}/participants participants:write

Custom values use top-level field IDs such as ff_456; multi-value custom fields may send list arrays. New participants default to one initial entry when initial_entries is omitted. If an update also supplies initial_entries, include an Idempotency-Key header so retries cannot duplicate bonus entries.

Body parameters

ParameterTypeNotes
participantsarrayUp to 50 participant objects per request.
update_existingbooleanWhen true, matching rows are updated instead of skipped.
trigger_workflowsbooleanOpt-in workflow trigger for newly created participants.
workflow_contact_permission_confirmedbooleanRequired alongside trigger_workflows to confirm consent.

Workflow triggering is opt-in. When enabled, Revup queues the promotion's active attached form_submitted workflow for newly created participants only. Updates, skipped duplicates, and failed rows do not trigger workflows. If no active attached workflow exists, the request still succeeds and the response reports the trigger as skipped.

Per-row workflow result

When workflows are requested, each successful row includes a workflow object with the immediate trigger result. trigger_status=queued means the trigger event was persisted; event_status is the current runtime state, usually pending immediately after the API request. trigger_status=skipped means no active attached workflow exists, not_triggered means the row was not newly created, and unknown means the participant was created but the trigger could not be immediately verified.

Request
curl https://revup.com/api/v1/promotions/123/participants \
  -H "x-api-key: rvup_v1_your_key_here" \
  -H "Idempotency-Key: crm-sync-2026-05-13-batch-0042" \
  -H "content-type: application/json" \
  -d '{
    "trigger_workflows": true,
    "workflow_contact_permission_confirmed": true,
    "participants": [
      {
        "email": "[email protected]",
        "first_name": "Ada",
        "ff_456": "VIP"
      }
    ]
  }'
Response 200 OK
{
  "success": true,
  "request_id": "a1b2c3d4e5f6",
  "data": {
    "created": 1,
    "updated": 0,
    "skipped": 0,
    "failed": 0,
    "idempotent_replays": 0,
    "results": [
      {
        "index": 0,
        "success": true,
        "action": "created",
        "participant_id": 98802,
        "identity_key": "email:[email protected]",
        "participant": {
          "id": 98802,
          "promotion_id": 123,
          "email": "[email protected]",
          "first_name": "Ada",
          "total_entries": 1
        },
        "workflow": {
          "trigger_requested": true,
          "trigger_status": "queued",
          "trigger_event_id": 789,
          "event_status": "pending",
          "message": "Workflow trigger event queued."
        }
      }
    ]
  }
}

Add bonus entries

Add bonus entries to an existing participant by email or phone. The request must include an Idempotency-Key header so retries cannot add duplicate entries. If both identifiers are sent, email is used.

POST /promotions/{promotion_id}/participants/entries participants:write

The endpoint appends a manual entry ledger row, recalculates the participant's total_entries, and returns the updated participant.

Body parameters

ParameterTypeNotes
emailstringLookup identifier. Preferred over phone.
phonestringFallback identifier when email is omitted.
entriesintegerNumber of bonus entries to add (positive integer).
titlestringOptional label stored on the ledger row.

An Idempotency-Key header is required. Replays with the same key return the original result without adding more entries.

Request
curl https://revup.com/api/v1/promotions/123/participants/entries \
  -H "x-api-key: rvup_v1_your_key_here" \
  -H "Idempotency-Key: crm-bonus-ada-2026-05-21" \
  -H "content-type: application/json" \
  -d '{
    "email": "[email protected]",
    "entries": 25,
    "title": "VIP launch bonus"
  }'
Response 200 OK
{
  "success": true,
  "request_id": "a1b2c3d4e5f6",
  "data": {
    "participant_id": 98801,
    "promotion_id": 123,
    "manual_key": "manual_points_api_7b1d2f9c6e4a8b0c1d3e5f7a9b2c4d6e",
    "entries_added": 25,
    "total_entries": 37,
    "participant": {
      "id": 98801,
      "promotion_id": 123,
      "email": "[email protected]",
      "total_entries": 37
    }
  }
}

List contacts

List contacts for the authenticated API key account. Default page size is 250. Promotion-restricted keys only see contacts linked to visible participants in allowed promotions.

GET /contacts contacts:read

Returns

FieldTypeNotes
idintegerAccount-level contact ID.
email, unique_id, first_name, middle_name, last_name, phonestring/nullCore identity fields.
address, address2, city, state, postal_code, countrystring/nullAddress fields when collected.
gender, birthdaystring/nullProfile fields when collected.
created_at, updated_atstring/nullYYYY-MM-DD HH:MM:SS timestamps.
created_at_epochinteger/nullUTC Unix timestamp for created_at.
ip_addressstring/nullLast stored IP address associated with the contact.
locationstring/nullStored location display value.
Request
curl https://revup.com/api/v1/contacts?limit=250 \
  -H "x-api-key: rvup_v1_your_key_here"
Response 200 OK
{
  "success": true,
  "request_id": "a1b2c3d4e5f6",
  "data": [
    {
      "id": 55421,
      "email": "[email protected]",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "phone": null,
      "created_at": "2026-05-10 14:22:11",
      "created_at_epoch": 1747145731,
      "ip_address": "203.0.113.42",
      "location": "Portland, OR, US"
    }
  ],
  "pagination": {
    "next_cursor": "eyJpZCI6NTU0MjF9",
    "has_more": true
  }
}

Create contact

Reserved for the coming contact write endpoint.

POST /contacts contacts:write

POST /contacts is coming soon. The contacts:write scope is available for future contact create/update support, but contact writes are not part of the live API v1 surface yet.

Response Coming soon
// Endpoint not yet available.
// The contacts:write scope can be reserved on API
// keys now so future calls do not need re-issuance.

List winners

List non-deleted winners and prize assignment details for a promotion. Default page size is 250.

GET /promotions/{promotion_id}/winners winners:read

Returns

FieldTypeNotes
idintegerWinner record ID.
promotion_idintegerPromotion ID this winner belongs to.
participant_idintegerParticipant/entrant ID selected as the winner.
contact_idinteger/nullAccount-level contact ID linked to the participant when available.
email, first_name, last_name, phonestring/nullSelected participant identity fields.
prize_idinteger/nullPrize row assigned to this winner when present.
prize_namestring/nullPrize name from the promotion prize table.
prize_valuestring/nullPrize value as a decimal string.
prize_currencystring/nullPrize currency code/text.
draw_idintegerWinner draw ID.
draw_group_number, draw_group_rankintegerGroup and rank for grouped draws or alternates.
is_current_winnerbooleanWhether this row is the current active winner for its draw/group slot.
statusstringwon, notified, claimed, disqualified, selected, or expired.
recovery_statusstring/nullRecovery/replacement workflow status when used.
date_drawnstring/nullPromotion-local draw timestamp in YYYY-MM-DD HH:MM:SS format.
fraud_flagbooleanWhether the winner row is marked with a fraud flag.
selection_index, selection_target, selection_total_weightinteger/nullStored weighted-selection audit values when available.
selection_hashstring/nullStored selection audit hash when available.
disqualified_at, promoted_at, announced_atstring/nullPromotion-local winner lifecycle timestamps.
promoted_from_winner_idinteger/nullPrior winner row this winner replaced when promoted.
winning_slot_start, winning_slot_endinteger/nullInstant-win slot start/end timestamp or offset when present.
random_sourcestring/nullDraw random source such as local or drand.
drand_roundinteger/nullDrand round used for the draw when applicable.
drand_requested_at, drand_round_published_atstring/nullDrand request and publication timestamps.
drand_beacon_id, drand_chain_hashstring/nullDrand beacon metadata when applicable.
randomness_valuestring/nullStored randomness value used for the draw when retained.
fallback_reasonstring/nullReason local fallback randomness was used when present.
Request
curl https://revup.com/api/v1/promotions/123/winners \
  -H "x-api-key: rvup_v1_your_key_here"
Response 200 OK
{
  "success": true,
  "request_id": "a1b2c3d4e5f6",
  "data": [
    {
      "id": 7711,
      "promotion_id": 123,
      "participant_id": 98801,
      "email": "[email protected]",
      "prize_id": 412,
      "prize_name": "Grand Prize",
      "prize_value": "500.00",
      "prize_currency": "USD",
      "draw_id": 88,
      "is_current_winner": true,
      "status": "notified",
      "date_drawn": "2026-06-16 12:00:00",
      "random_source": "drand"
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}

Retrieve a winner

Fetch a single winner record by ID. Returns the same shape as a list item.

GET /promotions/{promotion_id}/winners/{winner_id} winners:read

Path parameters

ParameterTypeNotes
promotion_idintegerPromotion ID.
winner_idintegerWinner record ID belonging to the promotion.
Request
curl https://revup.com/api/v1/promotions/123/winners/7711 \
  -H "x-api-key: rvup_v1_your_key_here"