---
title: "Orders & Transactions API"
description: "Create, retrieve, update, and complete orders, and charge transactions through the REST API."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.sparkcrm.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Orders & Transactions API

Manage orders and charge payments programmatically through the Spark CRM REST API.

The order lifecycle is split into distinct steps:

1. **Create an order** — records the customer, campaign, and products. No payment is attempted.
2. **Create a transaction** — attempts the payment immediately against an existing order.
3. **Complete the order** — fires the normal completion logic, including any applicable auto responders.

---

## Authentication

All endpoints require a Bearer token and return JSON. See [API Tokens](/settings/api-tokens).

```bash
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
```

| Endpoint | Method | Permission |
|----------|--------|------------|
| List orders | `GET /v1/orders` | `api:orders.view_any` |
| Retrieve order | `GET /v1/orders/{order_number}` | `api:orders.view` |
| Create order | `POST /v1/orders` | `api:orders.create` |
| Update order | `PATCH /v1/orders/{order_number}` | `api:orders.update` |
| Merge custom fields | `PATCH /v1/orders/{order_number}/custom-fields` | `api:orders.update` |
| Complete order | `POST /v1/orders/{order_number}/complete` | `api:orders.complete` |
| Create transaction | `POST /v1/transactions` | `api:transactions.create` |

---

## Create an Order

Creates an order in `pending` status. No payment is attempted — use the transactions endpoint to charge it.

```
POST /v1/orders
```

**Request:**
```bash
curl -X POST "https://api.sparkcrm.io/v1/orders" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
"campaign_id": "1024",
"currency": "USD",
"customer": {
  "email": "customer@example.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "phone": "+15551234567"
},
"shipping": {
  "address1": "123 Main St",
  "city": "Austin",
  "state": "TX",
  "postal_code": "78701",
  "country": "US"
},
"products": [
  { "offer_id": "5001", "quantity": 2 }
]
  }'
```

- `campaign_id` and `offer_id` are the campaign's / offer's `internal_id`.
- `shipping` is optional; when omitted the order is flagged for QA until an address is provided.

**Response** (`201 Created`):
```json
{
  "success": true,
  "message": "Order created successfully",
  "data": {
"order_number": "ORD-260708-00042",
"campaign_id": 1024,
"status": "pending",
"currency": "USD",
"cart": {
  "items": [
    { "id": 5001, "type": "offer", "quantity": 2, "unit_price": "49.00", "subtotal": 98 }
  ],
  "subtotal": "98.00",
  "shipping": "0.00",
  "tax": "0.00",
  "total": "98.00"
}
  }
}
```

Only the cart-level `subtotal`, `shipping`, `tax`, and `total` are returned as fixed 2-decimal strings. Item-level money is returned as-stored: `unit_price` and `shipping_price` are decimal strings, `subtotal` and `tax` are JSON numbers.

---

## Retrieve an Order

```
GET /v1/orders/{order_number}
```

**Request:**
```bash
curl -X GET "https://api.sparkcrm.io/v1/orders/ORD-260708-00042" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"
```

**Response** (`200 OK`):
```json
{
  "success": true,
  "data": {
"order_number": "ORD-260708-00042",
"status": "pending",
"currency": "USD",
"cart": { "total": "98.00" },
"transactions": []
  }
}
```

To list orders, call `GET /v1/orders` with optional `status`, `customer_id`, `campaign_id`, `date_from`, `date_to`, `search`, and `per_page` filters. The response includes a `pagination` object.

---

## Update an Order

Updates an order while it has not settled (e.g. `pending`). Once an order is paid or otherwise settled — completed, processing, refunded, voided, canceled, or in dispute — `PATCH /v1/orders/{order_number}` is rejected in full with `422 Order can no longer be edited`; no field is applied, including `custom_fields`, `utm_*`, and `affiliate`. Custom fields can still be merged on a settled order via `PATCH /v1/orders/{order_number}/custom-fields`.

```
PATCH /v1/orders/{order_number}
```

**Request:**
```bash
curl -X PATCH "https://api.sparkcrm.io/v1/orders/ORD-260708-00042" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
"products": [
  { "offer_id": "5001", "quantity": 3 }
],
"custom_fields": { "source": "phone" }
  }'
```

**Response** (`200 OK`):
```json
{
  "success": true,
  "message": "Order updated successfully",
  "data": {
"order_number": "ORD-260708-00042",
"status": "pending",
"cart": { "total": "147.00" }
  }
}
```

---

## Create a Transaction (charge)

Creating a transaction attempts the payment **immediately** — it is not a draft. The charge follows the campaign's configured payment routing: its payment orchestrator when one is assigned (the orchestrator picks the MID), otherwise its default gateway. A `gateway_id` override takes precedence over both. A campaign with neither an orchestrator nor a default gateway returns `422 Configuration Error` with `errors.no_gateway_available` set to `No payment gateway available for this order`.

The order's payment status is reflected (`processing` on an approved sale, `declined` on failure), but the order is **not** completed here. Completion and auto responders are handled by the complete endpoint.

```
POST /v1/transactions
```

**Request:**
```bash
curl -X POST "https://api.sparkcrm.io/v1/transactions" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
"order_number": "ORD-260708-00042",
"payment": {
  "method": "card",
  "card_number": "4111111111111111",
  "card_exp_month": "12",
  "card_exp_year": "2030",
  "card_cvv": "123"
}
  }'
```

- `amount` is optional; it defaults to the order's cart total.
- `gateway_id` (optional) overrides the campaign's payment routing — both its orchestrator and its default gateway — with an active gateway's `internal_id`. An unknown or inactive gateway returns `422`.

**Response** (`201 Created`, approved):
```json
{
  "success": true,
  "message": "Transaction processed successfully",
  "data": {
"transaction_number": "TXN-260708-000173",
"status": "completed",
"amount": "147.00",
"currency": "USD",
"gateway_id": 12,
"gateway_name": "Primary Gateway",
"card_brand": "visa",
"card_last_four": "1111"
  }
}
```

**Response** (`201 Created`, declined):
```json
{
  "success": false,
  "message": "Transaction was not approved",
  "data": {
"transaction_number": "TXN-260708-000174",
"status": "declined",
"gateway_response": "Insufficient Funds"
  }
}
```

---

## Complete an Order

Marks the order as completed and fires the normal completion logic, including any applicable **auto responders** (order confirmation emails), fulfillment, affiliate postbacks, and outbound webhooks. The call is idempotent.

```
POST /v1/orders/{order_number}/complete
```

**Request:**
```bash
curl -X POST "https://api.sparkcrm.io/v1/orders/ORD-260708-00042/complete" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"
```

**Response** (`200 OK`):
```json
{
  "success": true,
  "message": "Order marked as completed successfully",
  "data": {
"order_number": "ORD-260708-00042",
"status": "completed"
  }
}
```

---

## Related Topics

- [API Tokens](/settings/api-tokens) - Authentication and permissions
- [Coupons](/settings/coupons) - Discount codes applied to orders
- [Webhooks](/settings/webhooks) - Event notifications on order completion

Source: https://docs.sparkcrm.io/settings/orders-transactions-api/index.mdx
