# REST API Reference

Source: https://pushary.com/docs/web-push/server-sdk/api-reference
Last updated: 2026-05-11

> Direct HTTP API access for server-side integrations

Use the REST API to integrate Pushary with any language or platform. All endpoints require authentication via API key.

## Base URL [#base-url]

```
https://pushary.com/api/v1/server
```

## Authentication [#authentication]

All server API endpoints require a full API key passed via the `Authorization` header:

```bash
Authorization: Bearer pk_xxx.sk_xxx
```

The API key consists of two parts:

* `pk_xxx` - Public prefix (site key)
* `sk_xxx` - Secret portion (never expose client-side)

### Example Request [#example-request]

```bash
curl -X GET https://pushary.com/api/v1/server/subscribers \
  -H "Authorization: Bearer pk_abc123.sk_secret456"
```

### Authentication Errors [#authentication-errors]

| Status | Error        | Description                |
| ------ | ------------ | -------------------------- |
| 401    | Unauthorized | Missing or invalid API key |

```json
{
  "error": "Unauthorized",
  "message": "Invalid or missing API key. Use Authorization: Bearer pk_xxx.sk_xxx"
}
```

## Rate Limiting [#rate-limiting]

Rate limits vary by plan and are applied per API key:

| Plan       | Requests/minute |
| ---------- | --------------- |
| Free       | 100             |
| Starter    | 200             |
| Growth     | 500             |
| Enterprise | 1000            |

### Rate Limit Headers [#rate-limit-headers]

Every response includes rate limit information:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1704067200
```

### Rate Limit Exceeded [#rate-limit-exceeded]

```json
{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Please retry after 60 seconds.",
  "retryAfter": 60
}
```

## Pagination [#pagination]

List endpoints support cursor-based pagination:

| Parameter | Type    | Default | Max | Description              |
| --------- | ------- | ------- | --- | ------------------------ |
| `limit`   | integer | 100     | 500 | Number of items per page |
| `cursor`  | string  | -       | -   | Cursor for next page     |

### Response Format [#response-format]

```json
{
  "data": [...],
  "hasMore": true,
  "nextCursor": "abc123"
}
```

### Paginating Results [#paginating-results]

```bash
curl "https://pushary.com/api/v1/server/subscribers?limit=50&cursor=abc123" \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

***

## Send Notifications [#send-notifications]

Send push notifications directly to subscribers.

### POST /send [#post-send]

```bash
curl -X POST https://pushary.com/api/v1/server/send \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "New Message",
    "body": "You have a new notification",
    "url": "https://example.com/messages"
  }'
```

### Request Body [#request-body]

| Field           | Type      | Required | Description                 |
| --------------- | --------- | -------- | --------------------------- |
| `title`         | string    | Yes      | Notification title          |
| `body`          | string    | Yes      | Notification body text      |
| `url`           | string    | No       | Click action URL            |
| `iconUrl`       | string    | No       | Custom icon URL             |
| `imageUrl`      | string    | No       | Large image URL             |
| `subscriberIds` | string\[] | No       | Target specific subscribers |
| `externalIds`   | string\[] | No       | Target by external user IDs |
| `tags`          | string\[] | No       | Target by subscriber tags   |

### Targeting [#targeting]

If no targeting parameters are provided, the notification is sent to all active subscribers.

```bash
curl -X POST https://pushary.com/api/v1/server/send \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Welcome Back!",
    "body": "We missed you",
    "externalIds": ["user_123", "user_456"]
  }'
```

### Response [#response]

```json
{
  "success": true,
  "campaignId": "camp_abc123",
  "sent": 150,
  "limits": {
    "remaining": 9850,
    "limit": 10000
  }
}
```

***

## Subscribers [#subscribers]

Manage push notification subscribers.

### List Subscribers [#list-subscribers]

```
GET /subscribers
```

#### Query Parameters [#query-parameters]

| Parameter    | Type    | Description                                                      |
| ------------ | ------- | ---------------------------------------------------------------- |
| `limit`      | integer | Items per page (default: 100, max: 500)                          |
| `cursor`     | string  | Pagination cursor                                                |
| `status`     | string  | Filter by status: `active`, `unsubscribed`, `expired`, `bounced` |
| `externalId` | string  | Filter by external ID                                            |
| `tags`       | string  | Comma-separated tags filter                                      |

#### Example [#example]

```bash
curl "https://pushary.com/api/v1/server/subscribers?status=active&limit=50" \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-1]

```json
{
  "data": [
    {
      "id": "sub_abc123",
      "siteId": "site_xyz",
      "status": "active",
      "externalId": "user_123",
      "tags": ["premium", "newsletter"],
      "browser": "Chrome",
      "os": "Windows",
      "country": "US",
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-01-15T10:30:00Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "sub_def456"
}
```

### Get Subscriber [#get-subscriber]

```
GET /subscribers/:id
```

```bash
curl https://pushary.com/api/v1/server/subscribers/sub_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

### Update Subscriber [#update-subscriber]

```
PATCH /subscribers/:id
```

```bash
curl -X PATCH https://pushary.com/api/v1/server/subscribers/sub_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "tags": ["premium", "early-access"],
    "externalId": "user_456",
    "customData": {"plan": "pro"}
  }'
```

#### Request Body [#request-body-1]

| Field        | Type      | Description                |
| ------------ | --------- | -------------------------- |
| `tags`       | string\[] | Update subscriber tags     |
| `externalId` | string    | Update external identifier |
| `customData` | object    | Custom metadata            |

### Delete Subscriber [#delete-subscriber]

```
DELETE /subscribers/:id
```

```bash
curl -X DELETE https://pushary.com/api/v1/server/subscribers/sub_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-2]

```json
{
  "success": true
}
```

### Get Subscriber Count [#get-subscriber-count]

```
GET /subscribers/count
```

```bash
curl https://pushary.com/api/v1/server/subscribers/count \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-3]

```json
{
  "total": 1500,
  "active": 1200,
  "unsubscribed": 300
}
```

***

## Campaigns [#campaigns]

Create and manage notification campaigns.

### List Campaigns [#list-campaigns]

```
GET /campaigns
```

```bash
curl "https://pushary.com/api/v1/server/campaigns?limit=20" \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-4]

```json
{
  "data": [
    {
      "id": "camp_abc123",
      "name": "Welcome Campaign",
      "title": "Welcome!",
      "body": "Thanks for subscribing",
      "status": "draft",
      "totalTargeted": 0,
      "totalSent": 0,
      "totalDelivered": 0,
      "totalClicked": 0,
      "createdAt": "2024-01-15T10:30:00Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
```

### Create Campaign [#create-campaign]

```
POST /campaigns
```

```bash
curl -X POST https://pushary.com/api/v1/server/campaigns \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Product Launch",
    "title": "New Feature Available!",
    "body": "Check out our latest update",
    "actionUrl": "https://example.com/new-feature"
  }'
```

#### Request Body [#request-body-2]

| Field         | Type   | Required | Description            |
| ------------- | ------ | -------- | ---------------------- |
| `name`        | string | Yes      | Internal campaign name |
| `title`       | string | Yes      | Notification title     |
| `body`        | string | Yes      | Notification body      |
| `iconUrl`     | string | No       | Custom icon URL        |
| `imageUrl`    | string | No       | Large image URL        |
| `actionUrl`   | string | No       | Click action URL       |
| `scheduledAt` | string | No       | ISO 8601 schedule time |
| `segmentId`   | string | No       | Target segment ID      |

#### Response [#response-5]

Returns the created campaign object with status `201`.

### Get Campaign [#get-campaign]

```
GET /campaigns/:id
```

```bash
curl https://pushary.com/api/v1/server/campaigns/camp_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

### Update Campaign [#update-campaign]

```
PATCH /campaigns/:id
```

```bash
curl -X PATCH https://pushary.com/api/v1/server/campaigns/camp_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Updated Title",
    "body": "Updated body text"
  }'
```

#### Request Body [#request-body-3]

| Field         | Type   | Description            |
| ------------- | ------ | ---------------------- |
| `name`        | string | Campaign name          |
| `title`       | string | Notification title     |
| `body`        | string | Notification body      |
| `iconUrl`     | string | Custom icon URL        |
| `imageUrl`    | string | Large image URL        |
| `actionUrl`   | string | Click action URL       |
| `scheduledAt` | string | ISO 8601 schedule time |
| `status`      | string | Campaign status        |

### Delete Campaign [#delete-campaign]

```
DELETE /campaigns/:id
```

```bash
curl -X DELETE https://pushary.com/api/v1/server/campaigns/camp_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

### Send Campaign [#send-campaign]

```
POST /campaigns/:id/send
```

Send an existing campaign to all active subscribers.

```bash
curl -X POST https://pushary.com/api/v1/server/campaigns/camp_abc123/send \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Requirements [#requirements]

* Campaign must have status `draft` or `scheduled`
* Site must have VAPID keys configured

#### Response [#response-6]

Returns the updated campaign object with status `sending`.

### Pause Campaign [#pause-campaign]

```
POST /campaigns/:id/pause
```

Pause an active or sending campaign to temporarily stop notifications.

```bash
curl -X POST https://pushary.com/api/v1/server/campaigns/camp_abc123/pause \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Requirements [#requirements-1]

* Campaign must have status `active` or `sending`

#### Response [#response-7]

Returns the updated campaign object with status `paused`.

### Resume Campaign [#resume-campaign]

```
POST /campaigns/:id/resume
```

Resume a paused campaign to continue sending notifications.

```bash
curl -X POST https://pushary.com/api/v1/server/campaigns/camp_abc123/resume \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Requirements [#requirements-2]

* Campaign must have status `paused`

#### Response [#response-8]

Returns the updated campaign object with status `active`.

### Get Campaign Stats [#get-campaign-stats]

```
GET /campaigns/:id/stats
```

Get delivery and engagement statistics for a campaign.

```bash
curl https://pushary.com/api/v1/server/campaigns/camp_abc123/stats \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-9]

```json
{
  "totalSent": 1000,
  "totalDelivered": 950,
  "totalClicked": 85,
  "totalFailed": 50,
  "deliveryRate": 95.0,
  "clickRate": 8.95
}
```

| Field            | Type   | Description               |
| ---------------- | ------ | ------------------------- |
| `totalSent`      | number | Total notifications sent  |
| `totalDelivered` | number | Successfully delivered    |
| `totalClicked`   | number | Clicked by subscribers    |
| `totalFailed`    | number | Failed deliveries         |
| `deliveryRate`   | number | Delivery success rate (%) |
| `clickRate`      | number | Click-through rate (%)    |

***

## Templates [#templates]

Create reusable notification templates.

### List Templates [#list-templates]

```
GET /templates
```

```bash
curl "https://pushary.com/api/v1/server/templates" \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-10]

```json
{
  "data": [
    {
      "id": "tmpl_abc123",
      "name": "Welcome Template",
      "title": "Welcome to {{siteName}}!",
      "body": "Thanks for subscribing, {{userName}}",
      "iconUrl": null,
      "imageUrl": null,
      "actionUrl": "https://example.com/welcome",
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-01-15T10:30:00Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
```

### Create Template [#create-template]

```
POST /templates
```

```bash
curl -X POST https://pushary.com/api/v1/server/templates \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Order Confirmation",
    "title": "Order Confirmed!",
    "body": "Your order #{{orderId}} has been confirmed",
    "actionUrl": "https://example.com/orders/{{orderId}}"
  }'
```

#### Request Body [#request-body-4]

| Field       | Type   | Required | Description        |
| ----------- | ------ | -------- | ------------------ |
| `name`      | string | Yes      | Template name      |
| `title`     | string | Yes      | Notification title |
| `body`      | string | Yes      | Notification body  |
| `iconUrl`   | string | No       | Custom icon URL    |
| `imageUrl`  | string | No       | Large image URL    |
| `actionUrl` | string | No       | Click action URL   |

### Get Template [#get-template]

```
GET /templates/:id
```

```bash
curl https://pushary.com/api/v1/server/templates/tmpl_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

### Update Template [#update-template]

```
PATCH /templates/:id
```

```bash
curl -X PATCH https://pushary.com/api/v1/server/templates/tmpl_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Updated Title",
    "body": "Updated body with {{variable}}"
  }'
```

### Delete Template [#delete-template]

```
DELETE /templates/:id
```

```bash
curl -X DELETE https://pushary.com/api/v1/server/templates/tmpl_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

***

## Flows [#flows]

Manage automated notification sequences triggered by user behavior.

### List Flows [#list-flows]

```
GET /flows
```

#### Query Parameters [#query-parameters-1]

| Parameter | Type    | Description                                               |
| --------- | ------- | --------------------------------------------------------- |
| `limit`   | integer | Items per page (default: 100, max: 500)                   |
| `cursor`  | string  | Pagination cursor                                         |
| `status`  | string  | Filter by status: `draft`, `active`, `paused`, `archived` |

#### Example [#example-1]

```bash
curl "https://pushary.com/api/v1/server/flows?status=active" \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-11]

```json
{
  "data": [
    {
      "id": "flow_abc123",
      "siteId": "site_xyz",
      "name": "Welcome Series",
      "description": "Onboard new subscribers",
      "triggerType": "subscription",
      "status": "active",
      "executionCount": 150,
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-01-15T10:30:00Z",
      "steps": [
        {
          "id": "step_abc",
          "flowId": "flow_abc123",
          "stepOrder": 0,
          "stepType": "send_notification",
          "config": {
            "notification": {
              "title": "Welcome!",
              "body": "Thanks for subscribing"
            }
          }
        }
      ]
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
```

### Create Flow [#create-flow]

```
POST /flows
```

```bash
curl -X POST https://pushary.com/api/v1/server/flows \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Welcome Series",
    "description": "Onboard new subscribers",
    "triggerType": "subscription",
    "steps": [
      {
        "stepType": "send_notification",
        "config": {
          "notification": {
            "title": "Welcome!",
            "body": "Thanks for joining"
          }
        }
      },
      {
        "stepType": "delay",
        "config": {
          "delay": {
            "value": 1,
            "unit": "days"
          }
        }
      }
    ]
  }'
```

#### Request Body [#request-body-5]

| Field               | Type   | Required | Description                                                                                                       |
| ------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------- |
| `name`              | string | Yes      | Flow name                                                                                                         |
| `description`       | string | No       | Flow description                                                                                                  |
| `triggerType`       | string | Yes      | One of: `notification_click`, `notification_impression`, `notification_dismiss`, `subscription`, `unsubscription` |
| `triggerCampaignId` | string | No       | Campaign ID to trigger from (for notification triggers)                                                           |
| `steps`             | array  | No       | Array of flow steps                                                                                               |

#### Step Types [#step-types]

**Send Notification:**

```json
{
  "stepType": "send_notification",
  "config": {
    "notification": {
      "title": "Title",
      "body": "Body text",
      "iconUrl": "https://example.com/icon.png",
      "imageUrl": "https://example.com/image.png",
      "actionUrl": "https://example.com/action"
    }
  }
}
```

**Delay:**

```json
{
  "stepType": "delay",
  "config": {
    "delay": {
      "value": 24,
      "unit": "hours"
    }
  }
}
```

Units: `seconds`, `minutes`, `hours`, `days`

**Exit:**

```json
{
  "stepType": "exit",
  "config": {}
}
```

#### Response [#response-12]

Returns the created flow object with status `201`.

### Get Flow [#get-flow]

```
GET /flows/:id
```

```bash
curl https://pushary.com/api/v1/server/flows/flow_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

### Update Flow [#update-flow]

```
PATCH /flows/:id
```

```bash
curl -X PATCH https://pushary.com/api/v1/server/flows/flow_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated Welcome Series",
    "status": "paused",
    "steps": [
      {
        "stepType": "send_notification",
        "config": {
          "notification": {
            "title": "New Welcome Message",
            "body": "Updated content"
          }
        }
      }
    ]
  }'
```

#### Request Body [#request-body-6]

| Field               | Type   | Description                                          |
| ------------------- | ------ | ---------------------------------------------------- |
| `name`              | string | Flow name                                            |
| `description`       | string | Flow description                                     |
| `triggerType`       | string | Trigger type                                         |
| `triggerCampaignId` | string | Campaign ID                                          |
| `status`            | string | Flow status: `draft`, `active`, `paused`, `archived` |
| `steps`             | array  | Array of flow steps (replaces all existing steps)    |

### Delete Flow [#delete-flow]

```
DELETE /flows/:id
```

```bash
curl -X DELETE https://pushary.com/api/v1/server/flows/flow_abc123 \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

### Activate Flow [#activate-flow]

```
POST /flows/:id/activate
```

Activate a flow to start processing triggers. Flow must have at least one step.

```bash
curl -X POST https://pushary.com/api/v1/server/flows/flow_abc123/activate \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Requirements [#requirements-3]

* Flow must have status `draft`, `paused`, or `archived`
* Flow must have at least one step

#### Response [#response-13]

Returns the updated flow object with status `active`.

### Pause Flow [#pause-flow]

```
POST /flows/:id/pause
```

Pause an active flow to temporarily stop processing triggers.

```bash
curl -X POST https://pushary.com/api/v1/server/flows/flow_abc123/pause \
  -H "Authorization: Bearer pk_xxx.sk_xxx"
```

#### Response [#response-14]

Returns the updated flow object with status `paused`.

***

## Error Responses [#error-responses]

All errors follow a consistent format:

```json
{
  "error": "Error Type",
  "message": "Human-readable description"
}
```

### Error Codes [#error-codes]

| Status | Error                 | Description                                     |
| ------ | --------------------- | ----------------------------------------------- |
| 400    | Bad Request           | Missing required fields or invalid request body |
| 401    | Unauthorized          | Invalid or missing API key                      |
| 403    | Forbidden             | Plan limit exceeded or permission denied        |
| 404    | Not Found             | Resource does not exist                         |
| 429    | Too Many Requests     | Rate limit exceeded                             |
| 500    | Internal Server Error | Unexpected server error                         |

### Plan Limit Error [#plan-limit-error]

```json
{
  "error": "Notification limit exceeded",
  "message": "You've reached your monthly notification limit",
  "upgradeUrl": "https://pushary.com/pricing"
}
```

### Missing Fields Error [#missing-fields-error]

```json
{
  "error": "Missing required fields: title, body"
}
```