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

# Create Payment

> Accept payment requests from third-party payment apps

<Info>
  Third-party payment apps use this endpoint when they don't have a direct reserve account with you. They create a pending payment, then settle via an accepted settlement provider.
</Info>

## Two-Step Payment Flow

1. **Create payment** - Payment app calls `/payment/create` to create pending payment
2. **Settle payment** - Payment app settles via `/payment/settle` with a proof from an accepted settlement provider

This enables interoperability between payment apps and merchant gateways that don't have direct relationships.

## Implementation

```javascript theme={null}
app.post('/payment/create', verifyAuth, async (req, res) => {
  const { to, amount, currency, reference, memo, expiresAt, order } = req.body;
  const callerOcid = parseInt(req.headers['x-oc-id']);

  // 1. Verify merchant is registered
  const merchant = await db.getMerchantByOcid(to);
  if (!merchant) {
    return res.status(400).json({
      error: { code: 'MERCHANT_NOT_REGISTERED', message: 'Unknown merchant' }
    });
  }

  // 2. Create pending payment
  const txid = generateTxid();
  const payment = await db.createPayment({
    txid,
    callerOcid,
    merchantOcid: to,
    amount,
    currency,
    reference,
    memo,
    status: 'pending_settlement',
    expiresAt: expiresAt || Math.floor(Date.now() / 1000) + 3600,
    orderId: order?.id,
    orderUrls: order?.urls,
    createdAt: Date.now()
  });

  // 3. Optionally fetch and store order details
  if (order?.urls?.length > 0) {
    fetchAndStoreOrder(payment.id, order.urls);
  }

  // 4. Return settlement info
  res.json({
    status: 'pending_settlement',
    txid,
    amount,
    currency,
    expiresAt: payment.expiresAt,
    settlement: {
      accepts: ACCEPTED_SETTLEMENT_PROVIDERS // e.g., [100, 101, 102]
    }
  });
});
```

## Settlement Providers

The `settlement.accepts` array tells the payment app which OCIDs you'll accept proofs from:

```json theme={null}
{
  "settlement": {
    "accepts": [100, 101, 102]
  }
}
```

The payment app must:

1. Have an account with one of these providers
2. Execute a transfer to your OCID via that provider
3. Submit the signed proof to your `/payment/settle` endpoint

## Order Information

If payment is for an order, include order details:

```json theme={null}
{
  "order": {
    "id": "ord_abc123",
    "urls": ["https://merchant.example/orders/ord_abc123"]
  }
}
```

You can fetch the signed order from these URLs to validate the amount and merchant.


## OpenAPI

````yaml merchant-gateway-api/endpoint/merchant-gateway-api/openapi.json post /payment/create
openapi: 3.1.0
info:
  title: Opencharge Merchant Gateway API
  description: >-
    API specification for merchant gateways integrating with the Opencharge
    protocol. Merchant gateways provide hosted checkout pages for online
    merchants and process payments on their behalf.
  version: 0.1.0
  license:
    name: MIT
servers:
  - url: https://pay.gateway.example/opencharge
    description: Example merchant gateway Opencharge endpoint
security: []
paths:
  /payment/create:
    post:
      summary: Create payment
      description: >-
        Accept payment requests from third-party payment apps. Create a pending
        payment and return settlement information. The payment app will then
        settle via one of your accepted settlement providers using
        /payment/settle.
      operationId: createPayment
      parameters:
        - $ref: '#/components/parameters/X-OC-ID'
        - $ref: '#/components/parameters/X-OC-Timestamp'
        - $ref: '#/components/parameters/X-OC-Nonce'
        - $ref: '#/components/parameters/X-OC-Signature'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentCreateRequest'
            example:
              to: 500
              amount: '99.99'
              currency: USD
              reference: payment_123
              memo: Payment for electronics
              expiresAt: 1706503600
              order:
                id: ord_abc123
                urls:
                  - https://merchant.example/orders/ord_abc123
      responses:
        '200':
          description: Payment created, awaiting settlement
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentCreateResponse'
              example:
                status: pending_settlement
                txid: gateway_payment_456
                amount: '99.99'
                currency: USD
                expiresAt: 1706503600
                settlement:
                  accepts:
                    - 100
                    - 101
                    - 102
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Authentication failed or merchant not registered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  parameters:
    X-OC-ID:
      name: X-OC-ID
      in: header
      required: true
      description: Caller's OCID (Opencharge ID)
      schema:
        type: string
      example: '500'
    X-OC-Timestamp:
      name: X-OC-Timestamp
      in: header
      required: true
      description: Unix timestamp in seconds
      schema:
        type: string
      example: '1706500000'
    X-OC-Nonce:
      name: X-OC-Nonce
      in: header
      required: true
      description: Unique request identifier for replay protection
      schema:
        type: string
      example: req_abc123
    X-OC-Signature:
      name: X-OC-Signature
      in: header
      required: true
      description: secp256k1 ECDSA signature of the canonical request
      schema:
        type: string
      example: a1b2c3d4...7f1b
  schemas:
    PaymentCreateRequest:
      type: object
      required:
        - to
        - amount
        - currency
      description: Request from 3rd party payment app to create a pending payment
      properties:
        to:
          type: integer
          description: Merchant OCID to pay
        amount:
          type: string
        currency:
          type: string
        reference:
          type: string
        memo:
          type: string
        expiresAt:
          type: integer
        order:
          type: object
          properties:
            id:
              type: string
            urls:
              type: array
              items:
                type: string
                format: uri
    PaymentCreateResponse:
      type: object
      required:
        - status
        - txid
        - amount
        - currency
        - settlement
      description: Pending payment created, awaiting settlement
      properties:
        status:
          type: string
          enum:
            - pending_settlement
        txid:
          type: string
          description: Your payment transaction ID
        amount:
          type: string
        currency:
          type: string
        expiresAt:
          type: integer
        settlement:
          type: object
          required:
            - accepts
          properties:
            accepts:
              type: array
              items:
                type: integer
              description: OCIDs you accept for settlement
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - INVALID_SIGNATURE
                - TIMESTAMP_EXPIRED
                - NONCE_REUSED
                - UNKNOWN_OCID
                - INVALID_PROOF
                - PROOF_SIGNATURE_INVALID
                - ISSUER_NOT_ACCEPTED
                - ORDER_NOT_FOUND
                - ORDER_EXPIRED
                - TXID_NOT_FOUND
                - MERCHANT_NOT_REGISTERED
                - INSUFFICIENT_FUNDS
                - PAYMENT_NOT_FOUND
                - PAYMENT_EXPIRED
                - ACCOUNT_NOT_FOUND
            message:
              type: string
            details:
              type: object

````