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

# Create Deposit Order

> Create a deposit order and get a hosted payment page URL where your customer completes the payment.

## Overview

Creates a **deposit**: your customer pays money into an account held by a C2C member, and the amount, minus fees, is credited to your merchant wallet once the member confirms receipt.

C2C assigns an available member when the order is created and returns a `paymentPageUrl`. Redirect your customer to that hosted page. It opens on the [payment method](/guides/payment-methods) you requested in `walletType`: the customer sees the account number, Till ID or QR code to pay, sends the money from their wallet app, and confirms the payment on the page. See the [Deposit flow](/guides/deposit-flow) for the full lifecycle.

The order is **always accepted**. If no eligible member is available right now, it's created with status `Awaiting`, and a member is assigned when the customer opens the payment page.

| | |
| - | - |
| **API key** | Required |
| **Signature** | **Required**, in the body's `signature` field. See the [Signature Generation Guide](/api-reference/signature-guide) |
| **Idempotency-Key** | Required |

<Info>
  Deposits and withdrawals use the same endpoint. Set `orderType` to `"Deposit"` to create a deposit.
</Info>

## Headers

<ParamField header="C2C-API-Key" type="string" required>
  `mk_live_...`, your merchant API key. `Authorization: Bearer mk_live_...` is also accepted.
</ParamField>

<ParamField header="Idempotency-Key" type="string" required>
  Your unique key for this order attempt, up to 100 characters. Retrying with the same key returns the original order instead of creating a new one. See [Idempotency](/api-reference/idempotency).
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `application/json`
</ParamField>

## Request body

<ParamField body="orderType" type="string" required>
  Must be `"Deposit"`.
</ParamField>

<ParamField body="amount" type="number" required>
  Amount the customer pays, in `currency`. Must be greater than `0`, have at most 4 decimal places and be less than `100,000,000,000,000`.

  **Example:** `1500`
</ParamField>

<ParamField body="walletType" type="string" required>
  The [payment method](/guides/payment-methods) the customer pays with. C2C assigns a member with a receiving account of **exactly this method**, and the payment page opens directly on it.

  One of `JazzCash`, `JazzCashTillID`, `JazzCashQR`, `Easypaisa`, `TillID`, `EasypaisaQR`, `BankAccount`.

  | Value | The customer pays to |
  | - | - |
  | `JazzCash` | A JazzCash account number |
  | `JazzCashTillID` | A JazzCash Till ID |
  | `JazzCashQR` | A JazzCash QR code |
  | `Easypaisa` | An Easypaisa account number |
  | `TillID` | An Easypaisa Till ID |
  | `EasypaisaQR` | An Easypaisa QR code |
  | `BankAccount` | Accepted, but bank accounts aren't offered on the payment page for now: the page opens on the list of available methods and the customer picks one of the six above. |

  No method falls back to another. `JazzCash` and `Easypaisa` mean the account number only: request `JazzCashTillID` or `TillID` for a Till ID. If no account of the requested method is available, the order is accepted as `Awaiting`. On the payment page the customer can still switch to another method that is enabled for you.
</ParamField>

<ParamField body="currency" type="string" default="PKR">
  ISO currency code: `PKR`, `INR` or `BDT`. Defaults to `PKR`.
</ParamField>

<ParamField body="merchantOrderRef" type="string">
  Your own reference for this order, such as an invoice or cart ID. Up to 200 characters. It is echoed in [webhooks](/guides/webhooks), and you can [query the order by it](/api-reference/endpoints/query-order-status#query-by-merchantorderref).

  <Note>
    One live order per reference: if an order that is in progress or completed already uses this `merchantOrderRef`, the request is rejected with `409`. A reference whose earlier order failed can be reused. To retry a request, reuse the same `Idempotency-Key` instead. See [`merchantOrderRef` rules](/guides/order-status#merchantorderref-rules).
  </Note>
</ParamField>

<ParamField body="customerReference" type="string">
  Your identifier for the paying customer, for example a player ID. Up to 200 characters.
</ParamField>

<ParamField body="callbackUrl" type="string">
  Absolute `http(s)` URL that receives the `order.completed` / `order.failed` [webhooks](/guides/webhooks) for this order. Up to 500 characters. It must resolve to a public internet address: loopback, private and link-local addresses are refused at delivery time, and redirects aren't followed.

  If omitted, C2C uses the default callback URL set in your **Merchant Portal → Settings**. If neither is set, no webhook is sent and you must poll [order status](/api-reference/endpoints/query-order-status).
</ParamField>

<ParamField body="successUrl" type="string">
  Absolute `http(s)` URL, up to 500 characters. When the order completes, the hosted payment page sends the customer here, with `c2c_order_id`, `c2c_order_reference` and `c2c_status` appended. See [Returning the customer](/guides/hosted-payment-page#returning-the-customer-to-your-site).
</ParamField>

<ParamField body="failureUrl" type="string">
  Absolute `http(s)` URL, up to 500 characters. Where the hosted payment page sends the customer when the order is rejected, expires or is cancelled. The same parameters are appended.
</ParamField>

<ParamField body="metadata" type="string">
  Free-form string, for example JSON-encoded, stored with the order for reconciliation. Up to 1000 characters. It isn't returned in API responses or webhooks.
</ParamField>

<ParamField body="txnRefDigitsRequired" type="integer" default="4">
  `4` to `8`. Applies to the account number and Till ID methods only (`JazzCash`, `JazzCashTillID`, `Easypaisa`, `TillID`): how many trailing digits of the wallet transaction ID the customer enters on the payment page.

  It has no effect on a payment made with `JazzCashQR` or `EasypaisaQR`. Those methods don't ask for a transaction ID: the customer gives their JazzCash account number (`JazzCashQR`) or the last 4 digits of their Easypaisa IBAN (`EasypaisaQR`) instead. See [What the customer submits](/guides/payment-methods#what-the-customer-submits).
</ParamField>

<ParamField body="maxRetryCount" type="integer" default="3">
  `0` to `10`. Only used by withdrawals: it limits how often C2C reassigns an order to another member. It has no effect on deposits.
</ParamField>

<ParamField body="signature" type="string" required>
  32-character lowercase hex MD5 of the other top-level fields (lowercased keys in ASCII order, `key=value` joined with `&`, `null` and empty values skipped) followed directly by your signing secret. See the [Signature Generation Guide](/api-reference/signature-guide).

  **Example:** `f2eb65603d36507621fdfd64aba78974`
</ParamField>

## Response

<ResponseField name="data" type="object">
  <Expandable title="properties" defaultOpen>
    <ResponseField name="orderId" type="uuid">
      C2C's unique order ID. **Store it.** You need it for [status queries](/api-reference/endpoints/query-order-status), and it is the `orderId` in webhooks.
    </ResponseField>

    <ResponseField name="paymentPageUrl" type="string">
      Hosted payment page for this order. Redirect the customer here. The URL is pre-signed and stops working at `expiresAt`. Don't modify it, and don't expose it to anyone other than the paying customer.
    </ResponseField>

    <ResponseField name="status" type="string">
      Initial status: `Queued` when a member was assigned, or `Awaiting` when no eligible member was available yet. See [Order status](/guides/order-status).
    </ResponseField>

    <ResponseField name="stage" type="string">
      Lifecycle stage: `Assigned` or `Awaiting` for a new deposit. See [Lifecycle stages](/guides/order-status#lifecycle-stages).
    </ResponseField>

    <ResponseField name="merchantOrderRef" type="string | null">
      Your `merchantOrderRef`, or `null` if you didn't send one.
    </ResponseField>

    <ResponseField name="orderReference" type="string">
      C2C's human-readable reference, for example `ORD-20261008120620-3f6b`. Quote it to support.
    </ResponseField>

    <ResponseField name="expiresAt" type="string">
      ISO 8601 UTC time when the payment page link expires, **15 minutes** after creation.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  # "signature" is computed as described in the Signature Generation Guide.
  # This value is the guide's worked example (example signing secret).
  curl --request POST \
    --url https://api.c2cpayment.net/api/merchant/orders \
    --header "C2C-API-Key: $C2C_API_KEY" \
    --header "Content-Type: application/json" \
    --header "Idempotency-Key: INV-10045" \
    --data '{"orderType":"Deposit","amount":1500,"currency":"PKR","walletType":"JazzCash","merchantOrderRef":"INV-10045","customerReference":"player_12345","callbackUrl":"https://merchant.example.com/webhooks/c2c","signature":"56eff91b5ab0351471a2a8d457320230"}'
  ```

  ```javascript Node.js theme={null}
  // signBody(): see the Signature Generation Guide
  const payload = {
    orderType: 'Deposit',
    amount: 1500,
    currency: 'PKR',
    walletType: 'JazzCash',
    merchantOrderRef: 'INV-10045',
    customerReference: 'player_12345',
    callbackUrl: 'https://merchant.example.com/webhooks/c2c',
  };

  const response = await fetch(
    'https://api.c2cpayment.net/api/merchant/orders',
    {
      method: 'POST',
      headers: {
        'C2C-API-Key': process.env.C2C_API_KEY,
        'Content-Type': 'application/json',
        'Idempotency-Key': 'INV-10045',
      },
      body: JSON.stringify({ ...payload, signature: signBody(payload, process.env.C2C_SIGNING_SECRET) }),
    }
  );
  const { data } = await response.json();
  // Persist data.orderId, then redirect the customer to data.paymentPageUrl
  ```

  ```python Python theme={null}
  import os, requests

  # sign_body(): see the Signature Generation Guide
  payload = {
      "orderType": "Deposit",
      "amount": 1500,
      "currency": "PKR",
      "walletType": "JazzCash",
      "merchantOrderRef": "INV-10045",
      "customerReference": "player_12345",
      "callbackUrl": "https://merchant.example.com/webhooks/c2c",
  }

  response = requests.post(
      "https://api.c2cpayment.net/api/merchant/orders",
      json={**payload, "signature": sign_body(payload, os.environ["C2C_SIGNING_SECRET"])},
      headers={
          "C2C-API-Key": os.environ["C2C_API_KEY"],
          "Idempotency-Key": "INV-10045",
      },
  )
  data = response.json()["data"]
  # Persist data["orderId"], then redirect the customer to data["paymentPageUrl"]
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "data": {
      "orderId": "788fcae0-5214-403c-baa2-f318c0eb1b5b",
      "paymentPageUrl": "https://<payment-page-host>/pay?order_id=788fcae0-5214-403c-baa2-f318c0eb1b5b&expires=1791462080&signature=Xk3...&wallet=jazzcash",
      "status": "Queued",
      "orderReference": "ORD-20261008120620-3f6b",
      "expiresAt": "2026-10-08T12:21:20.605646Z",
      "stage": "Assigned",
      "merchantOrderRef": "INV-10045"
    }
  }
  ```

  ```json 200 Awaiting a member theme={null}
  {
    "data": {
      "orderId": "788fcae0-5214-403c-baa2-f318c0eb1b5b",
      "paymentPageUrl": "https://<payment-page-host>/pay?order_id=788fcae0-5214-403c-baa2-f318c0eb1b5b&expires=1791462080&signature=Xk3...&wallet=jazzcash",
      "status": "Awaiting",
      "orderReference": "ORD-20261008120620-3f6b",
      "expiresAt": "2026-10-08T12:21:20.605646Z",
      "stage": "Awaiting",
      "merchantOrderRef": "INV-10045"
    }
  }
  ```

  ```json 400 Validation error theme={null}
  {
    "error": "'Amount' must be greater than '0'."
  }
  ```

  ```json 401 Signature theme={null}
  {
    "success": false,
    "error": "Request signature verification failed. Sign the request as described in the signature guide.",
    "code": "SIGNATURE_INVALID",
    "traceId": "5b269362496001a7ed102e2d8cc50329"
  }
  ```

  ```json 403 Forbidden theme={null}
  {
    "error": "IP not in whitelist."
  }
  ```

  ```json 409 Reference in use theme={null}
  {
    "error": "merchantOrderRef 'INV-10045' is already used by order ORD-20261008120620-3f6b. Reuse the same Idempotency-Key to retry a request, or use a new reference for a new payment."
  }
  ```

  ```json 422 Idempotency-Key reused theme={null}
  {
    "error": "This Idempotency-Key was already used for a different order request."
  }
  ```
</ResponseExample>

## Error responses

| Status | When | Body |
| - | - | - |
| `400` | A field fails validation, for example amount ≤ 0, an amount with more than 4 decimal places or too large, an unknown currency, an invalid URL or a value that is too long | `{"error": "..."}`. Multiple messages are joined with `; ` |
| `400` | `Idempotency-Key` missing, malformed JSON, or an unknown `orderType`/`walletType` value | `application/problem+json` with an `errors` object |
| `401` | API key missing, invalid or revoked | Empty body |
| `401` | `signature` missing, malformed, invalid, or replayed under a different `Idempotency-Key` | `{"success": false, "error", "code", "traceId"}` |
| `403` | Merchant account not active, or caller IP not whitelisted | `{"error": "..."}` |
| `413` | Body larger than 64 KB | `{"success": false, "error", "code": "PAYLOAD_TOO_LARGE", "traceId"}` |
| `409` | `merchantOrderRef` is already used by an order that is in progress or completed | `{"error": "merchantOrderRef '...' is already used by order ORD-…. ..."}` |
| `422` | The payment method (`walletType`) is disabled for deposits on your account, for example `JazzCash deposits are disabled for this merchant.` or `JazzCashQR deposits are disabled for this merchant.` | `{"error": "..."}` |
| `422` | The `Idempotency-Key` was already used with different order terms | `{"error": "This Idempotency-Key was already used for a different order request."}` |

See [Errors](/api-reference/errors) for the complete error model.

<Tip>
  If a request was rejected (`400`, `409`, `422` …), you can fix it and reuse the same `Idempotency-Key`, because rejected requests don't consume the key.
</Tip>

## What happens next

1. Redirect the customer to `paymentPageUrl` **immediately**. The link expires after 15 minutes.
2. If the order is `Awaiting`, a member is assigned when the customer opens the payment page. Until one is online the page shows "Finding an available agent…" and re-checks every 10 seconds.
3. The customer pays and confirms on the page: with the last digits of the transaction ID, or on the QR methods by giving the account they pay from. The order moves to `AwaitingCustomerPayment` and then `AwaitingMemberConfirmation`.
4. The member confirms (`Completed`) or rejects (`Rejected`) the payment.
5. You receive a [webhook](/guides/webhooks), and you can [query the status](/api-reference/endpoints/query-order-status) at any time. If you set `successUrl` / `failureUrl`, the payment page sends the customer back to you.

<Warning>
  Fulfil the purchase only when the order status is `Completed`, never on the creation response.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Deposit flow" icon="diagram-project" href="/guides/deposit-flow">
    Full lifecycle, statuses and timeouts
  </Card>

  <Card title="Query order status" icon="magnifying-glass" href="/api-reference/endpoints/query-order-status">
    Track the order to completion
  </Card>

  <Card title="Payment methods" icon="credit-card" href="/guides/payment-methods">
    The six methods and how they are matched
  </Card>

  <Card title="Hosted payment page" icon="window-maximize" href="/guides/hosted-payment-page">
    What your customer sees
  </Card>

  <Card title="Webhooks" icon="webhook" href="/guides/webhooks">
    Get notified when the order completes
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.