> For the complete documentation index, see [llms.txt](https://glu.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://glu.gitbook.io/docs/use-cases/add-an-activity-to-a-contact.md).

# Add an activity to a contact

**Activities** power the contact timeline, trigger workflows, and feed into RFM (recency, frequency, monetary) scoring.&#x20;

All activities have a `spend` that is automatically applied to the contacts lifetime value or LTV.

***

#### Creating an activity

`POST /activities`

At minimum, provide the contact ID, activity type, source, and when it happened:

{% code title="" overflow="wrap" lineNumbers="true" %}

```json
{
  "contact": 1042,
  "type": "Purchase",
  "source": "website",
  "happenedAt": "2026-04-07T14:30:00+00:00",
  "spend": 4500,
  "currencyCode": "GBP"
}
```

{% endcode %}

The `spend` field is in the smallest currency unit — 4500 means £45.00 for GBP, or $45.00 for USD.

#### Activity types

The `type` field must be one of these values:

<table><thead><tr><th>Type</th><th>When to use</th><th width="250">Additional fields</th></tr></thead><tbody><tr><td><code>Booking</code></td><td>Hotel or venue reservation</td><td>Include a <code>booking</code> object (see below)</td></tr><tr><td><code>Checked in</code></td><td>Guest arrives at venue</td><td>—</td></tr><tr><td><code>Checked out</code></td><td>Guest departs venue</td><td>—</td></tr><tr><td><code>Purchase</code></td><td>Non-Glu purchase or transaction</td><td><code>spend</code>, <code>currencyCode</code></td></tr><tr><td><code>Shopify order</code></td><td>Order from Shopify</td><td>Typically created automatically</td></tr><tr><td><code>Gift card registered</code></td><td>Gift card added to a contact</td><td><code>giftCard</code> Id </td></tr><tr><td><code>Login</code></td><td>Member logged in</td><td>—</td></tr><tr><td><code>Connected to wifi</code></td><td>Guest connected to venue wifi</td><td>—</td></tr><tr><td><code>Membership started</code></td><td>Contact started a membership</td><td>—</td></tr><tr><td><code>Changed tier</code></td><td>Contact moved to a different tier</td><td>—</td></tr><tr><td><code>Membership cancelled</code></td><td>Contact cancelled membership</td><td>—</td></tr><tr><td><code>Referral invite created</code></td><td>Contact sent a referral</td><td><code>referralInvite</code> (IRI reference)</td></tr><tr><td><code>Referral invite completed</code></td><td>Referral was completed</td><td><code>referralInvite</code> (IRI reference)</td></tr><tr><td><code>Golf reservation</code></td><td></td><td></td></tr><tr><td><code>Table reservation</code></td><td></td><td></td></tr></tbody></table>

#### Recording a purchase

For purchases made outside of Glu (in-store POS, external e-commerce, etc.):

```json
{
  "contact": 1042,
  "type": "Purchase",
  "source": "YourPOS",
  "happenedAt": "2026-04-07T19:45:00+00:00",
  "spend": 12750,
  "currencyCode": "GBP",
  "externalReference": "TXN-98765"
}
```

The `externalReference` field is important for deduplication — if you send the same activity type with the same external reference twice, Glu will recognise it as a duplicate rather than creating two entries.

#### Deduplication

Glu deduplicates activities using two methods:

1. **By `externalReference`**: If an activity of the same type already exists with the same external reference within the organisation, the existing activity is returned instead of creating a duplicate.
2. **By `giftCard`**: For gift card related activities, if an activity already exists for the same gift card, it won't be duplicated.

Always include an `externalReference` when syncing activities from external systems to make your integration idempotent.

#### Retrieving a single activity

<mark style="color:green;">`GET`</mark>` ``/activities/{id}`

{% code title="Response" lineNumbers="true" expandable="true" %}

```json
{
  "id": 5678,
  "contact": 1042,
  "happenedAt": "2026-04-07T14:30:00+00:00",
  "createdAt": "2026-04-07T14:30:05+00:00",
  "updatedAt": "2026-04-07T14:30:05+00:00",
  "type": "Purchase",
  "source": "website",
  "externalReference": "TXN-98765",
  "spend": 4500,
  "currencyCode": "GBP"
}
```

{% endcode %}

### Custom fields

### Common integration patterns

#### Syncing purchases from your POS

Record every in-store transaction to build a complete picture of customer spending:

```
Your POS                         Your Server                     Glu API
  │                                  │                              │
  │── Sale completed ───────────────►│                              │
  │                                  │── POST /contacts ───────────►│
  │                                  │◄── Contact (id: 1042) ──────│
  │                                  │                              │
  │                                  │── POST /activities ─────────►│
  │                                  │   {                          │
  │                                  │     contact: 1042,           │
  │                                  │     type: "Purchase",        │
  │                                  │     spend: 4500,             │
  │                                  │     externalReference: "..." │
  │                                  │   }                          │
  │                                  │◄── Activity created ────────│
```

The contact's `totalSpend`, `lastInteractedAt`, and RFM scores update automatically.

#### Enriching contacts from your CRM

Sync custom attributes from an external CRM or data source:

```bash
# 1. Find the contact
curl -s -H "x-api-key: $GLU_API_KEY" \
  "https://api.glu.io/contacts?emailAddress[]=jane@example.com"

# 2. Set custom field values
curl -X POST -H "x-api-key: $GLU_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.glu.io/contacts/1042/custom-fields" \
  -d '{"fieldName": "external_crm_id", "value": "CRM-48291"}'

curl -X POST -H "x-api-key: $GLU_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.glu.io/contacts/1042/custom-fields" \
  -d '{"fieldName": "preferred_language", "value": "French"}'
```

#### Hotel PMS integration

Record bookings and check-in/check-out events from your property management system:

```bash
# 1. Record the booking
curl -X POST -H "x-api-key: $GLU_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.glu.io/activities" \
  -d '{
    "contact": 1042,
    "type": "Booking",
    "source": "mews",
    "happenedAt": "2026-04-07T10:00:00+00:00",
    "externalReference": "RES-2026-1234",
    "booking": {
      "checkIn": "2026-06-15T15:00:00+00:00",
      "checkOut": "2026-06-18T11:00:00+00:00",
      "numberOfGuests": 2,
      "roomType": "Suite",
      "total": 75000,
      "currencyCode": "GBP",
      "customerReference": "SMITH-0607",
      "purpose": "Leisure",
      "origin": "Direct"
    }
  }'

# 2. Record the check-in when it happens
curl -X POST -H "x-api-key: $GLU_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.glu.io/activities" \
  -d '{
    "contact": 1042,
    "type": "Checked in",
    "source": "mews",
    "happenedAt": "2026-06-15T15:22:00+00:00",
    "externalReference": "RES-2026-1234-CHECKIN"
  }'
```

#### Activities and workflows

Activities can trigger workflows. For example, a workflow with a `booking_created` trigger will automatically run when a Booking activity is created. This lets you build automations like:

* Send a welcome email when a booking is recorded
* Award loyalty points when a purchase activity is logged
* Upgrade a membership tier when spend thresholds are met

You don't need to do anything extra — just create the activity and any matching active workflows will execute.

### Tips

* **Always include `externalReference`** when syncing from external systems to prevent duplicates on retry.
* **Use `source`** to identify where the activity came from — this helps when debugging and when building workflow conditions.
* **Amounts are always in lowest denomination** — pence for GBP, cents for USD/EUR.
* **Custom field names are case-sensitive** — use the exact `fieldName` from the custom field definition.
* **Custom field values are validated** — the API will return a 422 error if the value doesn't match the field type or isn't in the allowed options for a Select field.
* **Contact lookup by email** — if you don't have the contact ID, use `GET /contacts?emailAddress[]=email@example.com` to find it first, or use `POST /contacts` which will create or update by email and return the contact with its ID.
