# Private Endpoints

Private endpoints cover trading, balances, account actions, and trading history.

**Service Hosts**

There is no single gateway. Each path prefix maps to its own service:

| Path prefix            | Host                                      |
| ---------------------- | ----------------------------------------- |
| `/orders/*`            | `https://order-service.outpoll.com`       |
| `/api/events/*`        | `https://event-service.outpoll.com`       |
| `/api/user-balances/*` | `https://wallet-mutator-view.outpoll.com` |
| `/api/history/*`       | `https://history-service.outpoll.com`     |
| `/api/deposit/*`       | `https://wallet-mutator-view.outpoll.com` |
| `/api/transactions`    | `https://wallet-mutator-view.outpoll.com` |
| `/auth/*`              | `https://auth-service.outpoll.com`        |

### Authentication

Trading and data endpoints use API key headers.

| Header                  | Description                             |
| ----------------------- | --------------------------------------- |
| `OUTPOLL-API-KEY`       | API key. Starts with `op_k_`            |
| `OUTPOLL-API-SIGNATURE` | Base64URL-encoded HMAC-SHA256 signature |
| `OUTPOLL-API-TIMESTAMP` | Unix timestamp in seconds               |

Build the signature payload as:

```
message = timestamp + method + path + body
```

Use only the path.

Do not include the full URL.

Do not include the query string.

Timestamps must be within **30 seconds** of server time.

### Signature example

Use this worked example for a signed `POST` request.

#### Input values

* API key: `op_k_abc123`
* API secret: `dGVzdF9zZWNyZXRfMTIzNDU2Nzg`
* timestamp: `1712500000`
* method: `POST`
* path: `/orders/market`

{% code title="body.json" %}

```json
{"e":"54ccea1a-16fd-469c-8018-84b375243e8a","o":"b21f6fd8-b9d1-4b9f-bb79-ef141e3dcb76","ba":"a1b2c3d4-...","qa":"078dcd98-928d-479f-8110-ff6d27e44de2","s":"BUY","am":50}
```

{% endcode %}

{% stepper %}
{% step %}

### Build the message

Concatenate `timestamp + method + path + body`.

{% code title="message.txt" %}

```
1712500000POST/orders/market{"e":"54ccea1a-16fd-469c-8018-84b375243e8a","o":"b21f6fd8-b9d1-4b9f-bb79-ef141e3dcb76","ba":"a1b2c3d4-...","qa":"078dcd98-928d-479f-8110-ff6d27e44de2","s":"BUY","am":50}
```

{% endcode %}
{% endstep %}

{% step %}

### Decode the secret

The secret is base64url encoded.

This value is already correctly padded.

{% code title="secret.txt" %}

```
dGVzdF9zZWNyZXRfMTIzNDU2Nzg
```

{% endcode %}

Decode it to raw bytes before signing.
{% endstep %}

{% step %}

### Compute the digest

Generate `HMAC-SHA256(secret_bytes, message)`.

The output is 32 raw bytes.
{% endstep %}

{% step %}

### Encode the signature

Base64url-encode the digest.

Strip any trailing `=` characters.

{% code title="signature.txt" %}

```
k7Hj9xQ2mN4pL1rT5vW8yB3cF6gJ0sD_eI2uA4wK7Zo
```

{% endcode %}
{% endstep %}

{% step %}

### Send the headers

Include the API key, signature, and timestamp headers.

{% code title="headers.http" %}

```http
OUTPOLL-API-KEY: op_k_abc123
OUTPOLL-API-SIGNATURE: k7Hj9xQ2mN4pL1rT5vW8yB3cF6gJ0sD_eI2uA4wK7Zo
OUTPOLL-API-TIMESTAMP: 1712500000
```

{% endcode %}
{% endstep %}
{% endstepper %}

{% hint style="info" %}
The body must match the exact JSON string sent on the wire. Any spacing or field order change will change the signature.
{% endhint %}

#### cURL example

Use this shell example to compute the signature and send the request with `curl`.

{% code title="signed\_market\_order.sh" %}

```bash
API_KEY='op_k_abc123'
API_SECRET='dGVzdF9zZWNyZXRfMTIzNDU2Nzg'
TIMESTAMP='1712500000'
METHOD='POST'
PATH='/orders/market'
BODY='{"e":"54ccea1a-16fd-469c-8018-84b375243e8a","o":"b21f6fd8-b9d1-4b9f-bb79-ef141e3dcb76","ba":"a1b2c3d4-...","qa":"078dcd98-928d-479f-8110-ff6d27e44de2","s":"BUY","am":50}'

MESSAGE="${TIMESTAMP}${METHOD}${PATH}${BODY}"

SECRET_B64="$(printf '%s' "$API_SECRET" | tr '_-' '/+' | awk '{ n = length($0) % 4; if (n == 2) printf "%s==", $0; else if (n == 3) printf "%s=", $0; else printf "%s", $0 }')"
SECRET_HEX="$(printf '%s' "$SECRET_B64" | base64 -d | xxd -p -c 256)"

SIGNATURE="$(
  printf '%s' "$MESSAGE" \
  | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$SECRET_HEX" -binary \
  | openssl base64 -A \
  | tr '+/' '-_' \
  | tr -d '='
)"

curl -X POST "https://order-service.outpoll.com${PATH}" \
  -H "Content-Type: application/json" \
  -H "OUTPOLL-API-KEY: ${API_KEY}" \
  -H "OUTPOLL-API-SIGNATURE: ${SIGNATURE}" \
  -H "OUTPOLL-API-TIMESTAMP: ${TIMESTAMP}" \
  --data "$BODY"
```

{% endcode %}

#### Python signature example

Use this example to sign and send a market order request directly to the order service.

{% code title="signed\_market\_order.py" %}

```python
import base64, hashlib, hmac, json, time, requests

API_KEY = "op_k_abc123"
API_SECRET = "dGVzdF9zZWNyZXRfMTIzNDU2Nzg"
HOST = "https://order-service.outpoll.com"
PATH = "/orders/market"
BODY = {
    "e": "54ccea1a-16fd-469c-8018-84b375243e8a",
    "o": "b21f6fd8-b9d1-4b9f-bb79-ef141e3dcb76",
    "ba": "a1b2c3d4-...",
    "qa": "078dcd98-928d-479f-8110-ff6d27e44de2",
    "s": "BUY",
    "am": 50,
}

body = json.dumps(BODY)
timestamp = str(int(time.time()))
message = timestamp + "POST" + PATH + body
secret_padded = API_SECRET + "=" * (4 - len(API_SECRET) % 4) if len(API_SECRET) % 4 else API_SECRET
secret_bytes = base64.urlsafe_b64decode(secret_padded)
signature = base64.urlsafe_b64encode(
    hmac.new(secret_bytes, message.encode(), hashlib.sha256).digest()
).decode().rstrip("=")

response = requests.post(
    HOST + PATH,
    headers={
        "OUTPOLL-API-KEY": API_KEY,
        "OUTPOLL-API-SIGNATURE": signature,
        "OUTPOLL-API-TIMESTAMP": timestamp,
        "Content-Type": "application/json",
    },
    data=body,
    timeout=10,
)

print(response.status_code, response.text)
```

{% endcode %}

#### JavaScript signature example

Use this example to sign and send the same request with `fetch`.

{% code title="signed\_market\_order.js" %}

```javascript
import crypto from "node:crypto";

const apiKey = "op_k_abc123";
const apiSecret = "dGVzdF9zZWNyZXRfMTIzNDU2Nzg";
const host = "https://order-service.outpoll.com";
const path = "/orders/market";
const body = JSON.stringify({
  e: "54ccea1a-16fd-469c-8018-84b375243e8a",
  o: "b21f6fd8-b9d1-4b9f-bb79-ef141e3dcb76",
  ba: "a1b2c3d4-...",
  qa: "078dcd98-928d-479f-8110-ff6d27e44de2",
  s: "BUY",
  am: 50,
});

const timestamp = String(Math.floor(Date.now() / 1000));
const message = timestamp + "POST" + path + body;
const secret = Buffer.from(
  apiSecret + "=".repeat((4 - apiSecret.length % 4) % 4),
  "base64url",
);
const signature = crypto
  .createHmac("sha256", secret)
  .update(message)
  .digest("base64url");

const response = await fetch(host + path, {
  method: "POST",
  headers: {
    "OUTPOLL-API-KEY": apiKey,
    "OUTPOLL-API-SIGNATURE": signature,
    "OUTPOLL-API-TIMESTAMP": timestamp,
    "Content-Type": "application/json",
  },
  body,
});

console.log(response.status, await response.text());
```

{% endcode %}

#### OutpollClient

Use a path-to-host map when one client needs to call multiple private services.

{% code title="outpoll\_client.py" %}

```python
import hmac, hashlib, base64, time, json, requests

SERVICE_MAP = {
    "/api/events": "https://event-service.outpoll.com",
    "/api/categories": "https://event-service.outpoll.com",
    "/api/tags": "https://event-service.outpoll.com",
    "/api/coins": "https://wallet-mutator-view.outpoll.com",
    "/api/user-balances": "https://wallet-mutator-view.outpoll.com",
    "/api/history": "https://history-service.outpoll.com",
    "/orders": "https://order-service.outpoll.com",
    "/auth": "https://auth-service.outpoll.com",
}

class OutpollClient:
    def __init__(self, api_key: str, api_secret: str):
        self.api_key = api_key
        self.api_secret = api_secret

    def _host(self, path: str) -> str:
        for prefix, host in SERVICE_MAP.items():
            if path.startswith(prefix):
                return host
        return "https://event-service.outpoll.com"

    def _sign(self, method: str, path: str, body: str = "") -> dict:
        timestamp = str(int(time.time()))
        message = timestamp + method + path + body
        padded = self.api_secret + "=" * (4 - len(self.api_secret) % 4) if len(self.api_secret) % 4 else self.api_secret
        secret_bytes = base64.urlsafe_b64decode(padded)
        signature = base64.urlsafe_b64encode(
            hmac.new(secret_bytes, message.encode(), hashlib.sha256).digest()
        ).decode().rstrip("=")
        return {
            "OUTPOLL-API-KEY": self.api_key,
            "OUTPOLL-API-SIGNATURE": signature,
            "OUTPOLL-API-TIMESTAMP": timestamp,
            "Content-Type": "application/json",
        }

    def get(self, path: str, params: dict = None):
        headers = self._sign("GET", path)
        return requests.get(self._host(path) + path, headers=headers, params=params)

    def post(self, path: str, data: dict = None):
        body = json.dumps(data) if data else ""
        headers = self._sign("POST", path, body)
        return requests.post(self._host(path) + path, headers=headers, data=body)

    def delete(self, path: str):
        headers = self._sign("DELETE", path)
        return requests.delete(self._host(path) + path, headers=headers)
```

{% endcode %}

### Sections

* [API Keys](/api/rest-api/private-endpoints/api-key-management/api-keys.md) for key creation, inspection, and revocation.
* [Orders](/api/rest-api/private-endpoints/orders.md) for limit, market, and TP/SL orders.
* [Portfolio](/api/rest-api/private-endpoints/portfolio.md) for portfolio-related endpoints.
* [Positions](/api/rest-api/private-endpoints/positions.md) for open positions and active orders.
* [Balances](/api/rest-api/private-endpoints/balances.md) for balance queries.
* [Deposit](/api/rest-api/private-endpoints/deposit.md) for the USDC deposit address.
* [History & Stats](/api/rest-api/private-endpoints/history-and-stats.md) for history coverage.
* [History](/api/rest-api/private-endpoints/history.md) for orders, trades, transactions, activity, and profile metrics.

### Example IDs

Examples use readable placeholders:

* `evt_btc_100k_2026` for an event
* `mkt_btc_100k_yes_no` for a market
* `asset_btc_100k_yes` for the YES asset
* `asset_usdc` for USDC
* `ord_7f3a9c2d` for an order
* `tpsl_4e2b1a90` for a TP/SL order

### Shared rules

See [FAQ](/api/faq.md) for rate limits, pagination, and common error handling.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.outpoll.com/api/rest-api/private-endpoints.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
