Skip to main content
For youGuidesBookings
API v1 - read APIs and webhooks

Build on Urba without scraping dashboards.

Use scoped organizer API keys to read events, attendees, orders, and webhook delivery logs. The API is designed for server-side integrations, stable contracts, cursor pagination, and clear failure modes.

Create an API keyOpenAPI JSON
First request
Verify a token and get the scoped organizer.
cURL
export URBA_API_TOKEN="urb_live_your_prefix_your_secret"

curl -sS https://urba.now/api/developer/v1/me \
  -H "Authorization: Bearer $URBA_API_TOKEN" \
  -H "Accept: application/json"
OverviewQuickstartAuthSync dataEndpointsWebhooksErrorsSecurity

Publish events anywhere

Sync Urba events to a venue site, artist page, CRM, newsletter builder, or analytics warehouse.

Know who is coming

Pull attendee names, emails, ticket tiers, and check-in state by event, by bounded organizer window, or exact email.

Reconcile money cleanly

Use order fields aligned to grossSales, netSales, organizerTaxCollected, and takeHome.

React without polling

Subscribe to webhooks for event, order, refund, dispute, attendee, and check-in changes.

Quickstart

Create a scoped key, verify it, then pull organizer data with copy-pasteable requests.

1

Create a key

Open an organizer profile, go to Developers, choose the minimum scopes, and save the token once.

2

Verify /me

Call /me from your server and store the organizer ID returned by the API.

3

Sync with cursors

Use limit and cursor for lists. Use webhooks or changed_since for incremental updates.

List events
curl -sS "https://urba.now/api/developer/v1/organizers/{organizerId}/events?limit=25" \
  -H "Authorization: Bearer $URBA_API_TOKEN"
List attendees or find one exact email
curl -sS "https://urba.now/api/developer/v1/events/{eventId}/attendees?limit=100" \
  -H "Authorization: Bearer $URBA_API_TOKEN"

curl -sS "https://urba.now/api/developer/v1/events/{eventId}/[email protected]" \
  -H "Authorization: Bearer $URBA_API_TOKEN"

Authentication and scopes

Developer API keys are profile-scoped personal access tokens. Send them only from trusted server code.

ScopeAllows
organizers:readRead the organizer profile attached to the token.
events:readList organizer events and retrieve event details.
attendees:readRead attendee lists, names, emails, ticket tiers, statuses, and check-in timestamps.
orders:readRead order summaries, buyer email, revenue fields, refund state, and payout vocabulary.
webhooks:readRead webhook endpoints and delivery history.
webhooks:writeCreate, update, disable, rotate, and redeliver webhook endpoints.

Token rules

  • Use Authorization: Bearer. Query-string tokens are rejected.
  • Cookies do not authenticate developer API routes.
  • No browser CORS is enabled for token-authenticated requests.
  • Tokens stop working if the creator loses owner or manager access.
  • Default expiry is 180 days. Maximum expiry is 365 days.

Pagination and filtering

Every list uses cursor pagination. Org-wide attendee and order exports must be bounded.

List conventions

  • Default limit is 50. Maximum limit is 100.
  • Use pagination.nextCursor until hasMore is false.
  • Attendees support exact email filtering.
  • Orders support exact buyer_email filtering.

Org-wide bounds

For organizer-wide attendee and order pulls, include one of event_id, changed_since, or both starts_after and starts_before. Event-date windows cannot exceed 90 days.

Incremental sync and exact email lookup
curl -sS "https://urba.now/api/developer/v1/organizers/{organizerId}/attendees?changed_since=2026-06-19T00:00:00.000Z&limit=100" \
  -H "Authorization: Bearer $URBA_API_TOKEN"

curl -sS "https://urba.now/api/developer/v1/organizers/{organizerId}/orders?event_id={eventId}&[email protected]" \
  -H "Authorization: Bearer $URBA_API_TOKEN"
Node fetch wrapper
const API_BASE_URL = 'https://urba.now/api/developer/v1'
const token = process.env.URBA_API_TOKEN

async function urba(path) {
  const response = await fetch(`${API_BASE_URL}${path}`, {
    headers: {
      Authorization: `Bearer ${token}`,
      Accept: 'application/json',
    },
  })

  if (response.status === 429) {
    const retryAfter = response.headers.get('retry-after')
    throw new Error(`Rate limited. Retry after ${retryAfter} seconds.`)
  }
  if (!response.ok) throw new Error(await response.text())
  return response.json()
}

const { data: me } = await urba('/me')
const { data: events } = await urba(`/organizers/${me.organizer.id}/events`)
const firstEvent = events[0]
const attendees = firstEvent ? await urba(`/events/${firstEvent.id}/attendees`) : null
console.log({ organizer: me.organizer.name, attendees: attendees?.data.length ?? 0 })

Endpoint reference

This table is generated from the same route registry that builds the OpenAPI document.

Auth

MethodPathScopesCost
GET/api/developer/v1/me
Inspect the current developer token and scoped organizer.
organizers:read1

Organizers

MethodPathScopesCost
GET/api/developer/v1/organizers
List organizers visible to the current token.
organizers:read1

Events

MethodPathScopesCost
GET/api/developer/v1/events/{eventId}
Get a single event by ID.
events:read1
GET/api/developer/v1/organizers/{organizerId}/events
List events for an organizer profile.
events:read1

Attendees

MethodPathScopesCost
GET/api/developer/v1/events/{eventId}/attendees
List attendees for one event.
attendees:read2
GET/api/developer/v1/organizers/{organizerId}/attendees
List attendees across an organizer profile with required bounding filters.
attendees:read5

Orders

MethodPathScopesCost
GET/api/developer/v1/events/{eventId}/orders
List orders for one event.
orders:read2
GET/api/developer/v1/organizers/{organizerId}/orders
List orders across an organizer profile with required bounding filters.
orders:read5

Webhooks

MethodPathScopesCost
GET/api/developer/v1/organizers/{organizerId}/webhooks
List webhook endpoints for an organizer profile.
webhooks:read1
POST/api/developer/v1/organizers/{organizerId}/webhooks
Create a webhook endpoint.
webhooks:write10
DELETE/api/developer/v1/organizers/{organizerId}/webhooks/{webhookId}
Disable a webhook endpoint.
webhooks:write10
GET/api/developer/v1/organizers/{organizerId}/webhooks/{webhookId}
Get a webhook endpoint.
webhooks:read1
PATCH/api/developer/v1/organizers/{organizerId}/webhooks/{webhookId}
Update or disable a webhook endpoint.
webhooks:write10

Webhook Deliveries

MethodPathScopesCost
GET/api/developer/v1/organizers/{organizerId}/webhooks/{webhookId}/deliveries
List recent delivery attempts for a webhook endpoint.
webhooks:read1
POST/api/developer/v1/organizers/{organizerId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver
Manually redeliver a recent delivery.
webhooks:write10

Webhooks

Use webhooks to keep integrations fresh without polling. Payloads are thin by default and link back to API resources.

Webhook payload
{
  "id": "evt_01J...",
  "type": "order.completed",
  "created": "2026-06-19T00:00:00.000Z",
  "apiVersion": "v1",
  "organizerId": "22222222-2222-4222-8222-222222222222",
  "eventId": "33333333-3333-4333-8333-333333333333",
  "data": {
    "object": {
      "id": "55555555-5555-4555-8555-555555555555",
      "object": "order",
      "apiUrl": "/api/developer/v1/events/33333333-3333-4333-8333-333333333333/orders"
    }
  }
}
Verify Urba-Webhook-Signature
import crypto from 'node:crypto'

export function verifyUrbaWebhook(rawBody, signatureHeader, signingSecret) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((part) => part.split('=', 2)),
  )
  const timestamp = Number(parts.t)
  if (!Number.isFinite(timestamp)) return false

  const now = Math.floor(Date.now() / 1000)
  if (Math.abs(now - timestamp) > 300) return false


  const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex')

  const received = Buffer.from(parts.v1 ?? '', 'hex')
  const expectedBuffer = Buffer.from(expected, 'hex')
  return received.length === expectedBuffer.length && crypto.timingSafeEqual(received, expectedBuffer)
}

Event types

event.createdevent.updatedevent.publishedevent.cancelledorder.completedorder.refundedorder.disputedattendee.createdattendee.updatedattendee.checked_inattendee.checked_out

Production endpoints must use HTTPS.

Deliveries time out after 10 seconds and retry for up to 72 hours with backoff.

Manual redelivery is available for 14 days. Delivery logs are retained for 30 days.

Errors and rate limits

Every response includes a requestId. Use it when debugging support issues or matching logs.

Error envelope
{
  "error": {
    "code": "INSUFFICIENT_SCOPE",
    "message": "This token is missing the attendees:read scope.",
    "requestId": "req_...",
    "docUrl": "https://urba.now/developers#auth"
  }
}

Rate-limit contract

  • 2,000 points per hour per token.
  • 48,000 points per day per token.
  • 100 points per minute burst.
  • 5 concurrent requests per token.
  • Read X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After before retrying.

Security checklist

The API is intentionally narrow: server-side tokens, explicit scopes, no dashboard cookies, no browser CORS, and safe payloads.

Do

  • Store tokens in server-side secret storage.
  • Use the smallest scope set needed.
  • Rotate keys on staff or vendor changes.
  • Use webhooks instead of tight polling loops.

Excluded from v1

  • QR secrets and scan tokens
  • Stripe payment method and charge IDs
  • raw IP addresses and user agents
  • invite codes
  • internal ranking and AI fields

Contract files

Use the OpenAPI document to generate clients, validate schemas, or import the API into Postman, Bruno, Insomnia, or your gateway tooling.

Download OpenAPI JSON

If a key leaks

  1. Open the organizer Developer settings and choose Compromised or Revoke for the key.
  2. Create a new key with the smallest scopes required.
  3. Move the new key into server-side secret storage and redeploy the integration.
  4. Review the Security tab for new IP fingerprints, high-volume attendee/order exports, 404 probing, and rate-limit continuation.

AI builder guardrails

  • Put URBA_API_TOKEN in .env.local or a production secret manager.
  • Never use NEXT_PUBLIC_URBA_API_TOKEN, client components, mobile apps, or browser fetches for token-authenticated calls.
  • Ask AI tools to build a server route or backend job that reads the token from process environment.
  • Commit only placeholders such as URBA_API_TOKEN=replace_me.

Need help with an integration?

Send the requestId, endpoint, and what you are trying to build. Do not send full API tokens in support messages.

Contact support
For youSearchGuidesBookingsProfile

Urba is a local discovery platform offering event ticketing, reservations, guides, and more for people looking for things to do in their city.

For organizers

  • Event ticketing software
  • Ticketing pricing
  • QR ticket scanner
  • Organizer payouts
  • Organizer resources
  • Organizer FAQ
  • Contact organizer support

Explore Calgary

  • Things to do in Calgary
  • Calgary events tonight
  • Calgary dining
  • Calgary nightlife
  • Calgary experiences
  • Calgary concerts
  • Calgary comedy shows
  • Calgary reservations

Discover

  • Upcoming events
  • City guides
  • Search events
  • All cities
  • Local curators

Popular cities

  • Toronto events
  • Montreal events
  • Vancouver events
  • Calgary events
  • Edmonton events
  • Ottawa events
  • Winnipeg events
  • Halifax events
  • Victoria events

Trust

  • About Urba
  • Trust center
  • Customer support
  • Press and media kit
  • Terms
  • Privacy
  • Community guidelines
  • Sitemap
  • Platform facts

© 2026 Urba Inc.

Maps © OpenStreetMap contributors, © CARTO