Skip to main content
A custom Object is an entity in your system — a vehicle, ticket, asset, client — paired with a permanent short scan URL of the form https://award.ee/o/{public_slug}. You decide what type means, what goes in metadata, and where scans route to.
{
  "id": "3a00bde3-f3b3-44a9-a16b-5d694e145440",
  "type": "vehicle",
  "external_id": "VIN-1HGCM82633A123456",
  "public_slug": "a1b2c3d",
  "url": "https://award.ee/o/a1b2c3d",
  "name": "2024 Toyota Hilux",
  "destination": {
    "type": "chatbot",
    "chatbot": "8f3a9d2e-1b4c-4f5d-9e8a-7c3b2a1d0f9e"
  },
  "metadata": { "color": "blue", "owner": "fleet-3" },
  "is_active": true
}

When to reach for Objects

Objects are for any custom entity in your system that needs a permanent scan URL on top of it — typed by you, indexed by your external_id. The shape is intentionally generic so you can model whatever doesn’t fit a built-in resource. Typical examples:
  • Customer records / Clients — CRM contacts, accounts, leads.
  • Receipts / Invoices — issued documents, statements.
  • Vehicles, assets, equipment — fleet, tooling, serialised inventory.
  • Tickets, work orders — support cases, repair jobs, service tasks.
  • Anything custom — a row in your domain that needs a scan handle.
How Objects compare to the other entity types:

Objects

Anything else. You bring the type and external_id; we mint and own the slug. Built for integrations.

Products

Physical SKU-keyed catalog items, indexed by GTIN. For retail goods with barcodes. See Products.

QR Codes

Printed-first generic short URLs. Created in the dashboard and shipped on stickers. See QR Codes.

Idempotency by external_id

external_id is your identifier. Pass it on POST /objects and the call is idempotent on the pair (org_id, external_id). Replaying the same external_id never creates a duplicate row — it updates the existing one with whatever you sent and returns the same id and public_slug. The status code tells you what happened:
  • 201 Created — new row inserted
  • 200 OK — existing row was updated
curl -X POST https://api.awardee.dev/v1/objects \
  -H "Authorization: Bearer aw_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "vehicle",
    "externalId": "VIN-1HGCM82633A123456",
    "name": "2024 Toyota Hilux",
    "metadata": { "color": "blue", "fleet": 3 }
  }'
Objects without an external_id aren’t deduplicated — every POST creates a fresh row. Always pass an external_id from CRM/upstream syncs.
You can also look up by external_id without writing:
GET /objects?external_id=VIN-1HGCM82633A123456

Destinations

Every Object can route scans to one of four destinations. Set destinationType and the matching target ID/URL on create or update.
destinationTypeCompanion fieldWhat happens on scan
chatbotdestinationChatbot (UUID)Redirects to the chatbot’s public URL.
pagedestinationPage (UUID)Renders the page.
knowledge_basedestinationKnowledgeBase (UUID)Lands on the KB index.
urldestinationUrl (string)302 to an external URL.
When destinationType is null, the scan URL serves a default landing page.
curl -X PATCH https://api.awardee.dev/v1/objects/3a00bde3-f3b3-44a9-a16b-5d694e145440 \
  -H "Authorization: Bearer aw_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "destinationType": "chatbot",
    "destinationChatbot": "8f3a9d2e-1b4c-4f5d-9e8a-7c3b2a1d0f9e"
  }'

Properties

properties are typed key/value pairs attached to an Object. They power variable substitution inside chatbot prompts and pages ({{object.<type>.<key>}}) and show up in the dashboard as structured fields. Properties live at their own sub-resource:
  • GET /objects/{id}/properties
  • PUT /objects/{id}/propertiesreplace the full set
PUT is replace-only. Pass every property you want to keep; anything omitted gets removed. Keys are unique per object — you can’t ship the same key twice in a request.
curl -X PUT https://api.awardee.dev/v1/objects/3a00bde3-f3b3-44a9-a16b-5d694e145440/properties \
  -H "Authorization: Bearer aw_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": [
      { "key": "color",    "value": "blue" },
      { "key": "mileage",  "value": "42500" },
      { "key": "owner",    "value": "fleet-3" }
    ]
  }'
Properties can also be set inline on POST /objects by including a properties: [...] array on the create payload. The same replace semantics apply.

URL params

url_params are static query-string params merged into the scan-redirect URL. Use them to pass tracking, source attribution, or any static context downstream.
  • GET /objects/{id}/url-params
  • PUT /objects/{id}/url-paramsreplace the full set
Live params (whatever the visitor has on award.ee/o/<slug>?...) win on key collision.
curl -X PUT https://api.awardee.dev/v1/objects/3a00bde3-f3b3-44a9-a16b-5d694e145440/url-params \
  -H "Authorization: Bearer aw_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "url_params": [
      { "key": "utm_source",  "value": "qr" },
      { "key": "utm_medium",  "value": "sticker" }
    ]
  }'

The scan-redirect flow

1

Visitor scans

Visitor hits https://award.ee/o/{public_slug}. The slug is generated when the Object is created and never changes.
2

We resolve

We look up the Object, merge url_params (static) with the live query string (live wins), and emit an object.scanned webhook.
3

We redirect

Routed by destinationType: chatbot URL, page render, KB index, or external URL. If no destination is set, the default landing page is served.
Scans are never directly creatable through the API — they happen when someone actually loads the scan URL. To get notified, subscribe to the object.scanned webhook (see below).

Deletion

DELETE /objects/{id} removes the object. Future scans of its slug 404, and subsequent reads of the id return 404 not_found. Slugs are never reused — a deleted object’s public_slug will not be reassigned to a new object, even if you upsert a fresh row with the same external_id.

Webhook events

Four events fire over an Object’s lifecycle. Payloads ship inside the standard event envelope — see Webhooks overview.
object.created
event
New Object row inserted. Fires once per (org_id, external_id).
object.updated
event
Any field on the row changed — including upsert replays that touched columns.
object.scanned
event
Someone loaded award.ee/o/{public_slug}. Use this to drive real-time notifications.
object.deleted
event
Object was deleted. Slug stays reserved and won’t be reassigned.
Sample object.created / object.updated payload (data field):
{
  "objectId": "3a00bde3-f3b3-44a9-a16b-5d694e145440",
  "orgId": "c1f5b2a7-9e8d-4f6a-b3c4-d5e6f7a8b9c0",
  "type": "vehicle",
  "externalId": "VIN-1HGCM82633A123456",
  "publicSlug": "a1b2c3d",
  "name": "2024 Toyota Hilux",
  "description": null,
  "metadata": { "color": "blue", "fleet": 3 },
  "destination": {
    "type": "chatbot",
    "chatbot": "8f3a9d2e-1b4c-4f5d-9e8a-7c3b2a1d0f9e",
    "page": null,
    "knowledgeBase": null,
    "url": null
  },
  "isActive": true,
  "createdAt": "2026-05-23T10:00:00Z",
  "updatedAt": "2026-05-23T10:00:00Z"
}
Sample object.deleted payload:
{
  "objectId": "3a00bde3-f3b3-44a9-a16b-5d694e145440",
  "orgId": "c1f5b2a7-9e8d-4f6a-b3c4-d5e6f7a8b9c0",
  "type": "vehicle",
  "externalId": "VIN-1HGCM82633A123456",
  "publicSlug": "a1b2c3d",
  "deletedAt": "2026-05-23T11:00:00Z"
}

Next

Object reference

Every field on the Object resource.

Chatbots

The most common scan destination.