# Rust

URL: https://pieowl.com/docs/sdks/rust





Pieowl doesn't ship a Rust crate. You send events from Rust with a plain HTTP request to the [Track API](/docs/api/track). Rust has no HTTP client in its standard library, so the example below uses the common `reqwest` and `serde_json` crates.

Before you start [#before-you-start]

You need a client ID and a client secret. Find them in the dashboard under **Settings → Developers → Keys**. Server requests must include the secret, so keep it on your server and load it from an environment variable.

Add the crates to your `Cargo.toml`:

```toml title="Cargo.toml"
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
```

Send an event [#send-an-event]

Every request is a `POST` to `https://api.pieowl.com/track` with a JSON body of `{ "type": ..., "payload": ... }`.

```rust title="src/pieowl.rs"
use serde_json::{json, Value};
use std::time::Duration;

const TRACK_URL: &str = "https://api.pieowl.com/track";

pub async fn send(
    client: &reqwest::Client,
    event_type: &str,
    payload: Value,
) -> Result<reqwest::StatusCode, reqwest::Error> {
    let response = client
        .post(TRACK_URL)
        .timeout(Duration::from_secs(5))
        .header("pieowl-client-id", std::env::var("PIEOWL_CLIENT_ID").unwrap_or_default())
        .header("pieowl-client-secret", std::env::var("PIEOWL_CLIENT_SECRET").unwrap_or_default())
        // Optional: forward the visitor's IP for location data
        // .header("pieowl-client-ip", visitor_ip)
        .json(&json!({ "type": event_type, "payload": payload }))
        .send()
        .await?;
    Ok(response.status())
}
```

Create one `reqwest::Client` and reuse it for every call.

Usage [#usage]

Tracking events [#tracking-events]

```rust
let client = reqwest::Client::new();

send(&client, "track", json!({
    "name": "signup",
    "profileId": "user_123", // optional
    "properties": { "plan": "pro" }
})).await?;
```

Identifying users [#identifying-users]

```rust
send(&client, "identify", json!({
    "profileId": "user_123", // required
    "firstName": "Joe",
    "lastName": "Doe",
    "email": "joe@doe.com",
    "properties": { "tier": "premium" }
})).await?;
```

Incrementing and decrementing properties [#incrementing-and-decrementing-properties]

`value` is optional and defaults to 1.

```rust
send(&client, "increment", json!({ "profileId": "user_123", "property": "visits", "value": 1 })).await?;
send(&client, "decrement", json!({ "profileId": "user_123", "property": "credits", "value": 1 })).await?;
```

Tracking revenue [#tracking-revenue]

A purchase is a `revenue` event with these properties:

* `__amount`: in normal units, like `49.99`, not cents.
* `__currency`: an ISO 4217 code, like `EUR`. Optional, your site currency by default.
* `__orderId`: your order number. The same order sent twice counts once.
* `__deviceId`: the visitor's device ID, from `pieowl.getDeviceId()` in the browser. The purchase is credited to their visit.

For a refund, send the same event with `__refund` set to true. Leave out `__amount` to refund the whole order. See [Revenue attribution](/docs/revenue-attribution).

```rust
send(&client, "track", json!({
    "name": "revenue",
    "properties": {
        "__amount": 49.99,
        "__currency": "EUR",
        "__orderId": "A-1001",
        "__deviceId": device_id
    }
})).await?;

// Refund the whole order
send(&client, "track", json!({
    "name": "revenue",
    "properties": { "__orderId": "A-1001", "__refund": true }
})).await?;
```

Good to know [#good-to-know]

* **Errors:** `send` returns the HTTP status. A `2xx` status means Pieowl accepted the request. Network errors come back as `reqwest::Error`.
* **Don't block requests:** In a web server, send events with `tokio::spawn` so a slow call never holds up the response.
* **More event types:** Groups and the full request schema are in the [Track API reference](/docs/api/track).
