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

# Create order

> Accepts plaintext payload, applies markup to KES rate, hashes message, and submits order.

Create a new **on-ramp** or **off-ramp** order.

**What happens**

* Validates request and locks the quote as `rate_used`.
* For **OFFRAMP**, the service submits the on-chain tx for you (no gas from client).
* Returns the creation transaction hash **`tx_hash`** immediately.

**Response envelope**
All responses use:

```json
{ "status": "success|error", "message": "string", "data": { ... } }
```

**Success `data` fields**

* `tx_hash` — creation transaction hash (use with `GET /orders/tx/{tx_hash}`).
* `status` — order state: `submitted | processing | settled | failed | refunded`.
* `rate_used` — FX rate applied when the quote was locked.
* `amount_sent` — token amount in 6 decimals units (e.g., `0.71234` USDC).
* `fiat_paid` — fiat amount charged/expected.

**Example — 201 Created**

```json
{
  "status": "success",
  "message": "Order submitted",
  "data": {
    "tx_hash": "0xabc123...",
    "status": "submitted",
    "rate_used": 142.1234,
    "amount_sent": 12.34,
    "fiat_paid": 1750
  }
}
```

**Error shapes (examples)**
400 insufficient allowance:

```json
{ "status": "error", "message": "Approve the contract to spend your tokens before OffRamp.", "data": { "required": 79218430, "current": 0 } }
```

401 missing/invalid key:

```json
{ "status": "error", "message": "Missing API key", "data": null }
```

**Track the order**

* `GET /orders/tx/{tx_hash}` — fetch current status and details.
* Webhooks — configure a webhook URL + secret on your API key to receive async updates.

**Auth**
Send `X-API-Key: <key>` with every request.


## OpenAPI

````yaml api-reference/openapi.json post /orders/create
openapi: 3.1.0
info:
  title: Element Aggregator API for B2B
  description: >-
    The Element Aggregator acts as a bridge between fiat and blockchain smart
    contracts. It handles payment processing, event listening, and order
    management, ensuring seamless coordination between Web2 and Web3 ecosystems.
  version: 1.0.0
servers:
  - url: https://sandbox.elementpay.net
security: []
paths:
  /orders/create:
    post:
      tags:
        - Order Endpoints
      summary: Create order from plaintext payload
      description: >-
        Accepts plaintext payload, applies markup to KES rate, hashes message,
        and submits order.
      operationId: create_order_plain_orders_create_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderPlainSchema'
        required: true
      responses:
        '200':
          description: Order submitted
          content:
            application/json:
              schema: {}
              example:
                status: success
                message: Order submitted
                data:
                  tx_hash: 0xabc123...
                  status: submitted
                  rate_used: 142.1234
                  amount_sent: 12.34
                  fiat_paid: 1750
        '400':
          description: Insufficient allowance or bad request
          content:
            application/json:
              examples:
                insufficient_allowance:
                  summary: Allowance too low
                  value:
                    status: error
                    message: Approve the contract to spend your tokens before OffRamp.
                    data:
                      required: 79218430
                      current: 0
                insufficient_balance:
                  summary: Balance too low
                  value:
                    status: error
                    message: Insufficient token balance for OffRamp.
                    data:
                      required: 79218430
                      current: 50000000
                generic_bad_request:
                  summary: Other client error
                  value:
                    status: error
                    message: Invalid transaction details
        '401':
          description: Unauthorized / Missing or invalid API key
          content:
            application/json:
              examples:
                Missing Api Key:
                  summary: No API key provided
                  value:
                    status: error
                    message: Missing API key
                    data: null
                Invalid Or RevokedApiKey:
                  summary: Invalid or revoked key
                  value:
                    status: error
                    message: Invalid or revoked API key
                    data: null
        '422':
          description: Validation error
          content:
            application/json:
              examples:
                invalid_user_address:
                  summary: Bad EVM address format
                  value:
                    status: error
                    message: Validation error
                    data:
                      errors:
                        - type: value_error.address
                          loc:
                            - body
                            - user_address
                          msg: >-
                            Invalid EVM address; must be 0x followed by 40 hex
                            chars.
                          input: '0x4F0741E6bfCCF8D256E8ef803Cc2653dfbB9558'
                placeholder_token:
                  summary: Template variable instead of address
                  value:
                    status: error
                    message: Validation error
                    data:
                      errors:
                        - type: value_error.placeholder
                          loc:
                            - body
                            - token
                          msg: >-
                            Looks like a template variable; provide a real
                            address.
                          input: '{{BASE_USDC}}'
                missing_amount_fiat:
                  summary: Required field missing
                  value:
                    status: error
                    message: Validation error
                    data:
                      errors:
                        - type: missing
                          loc:
                            - body
                            - fiat_payload
                            - amount_fiat
                          msg: Field required
        '500':
          description: Internal error
          content:
            application/json:
              example:
                status: error
                message: Internal error occurred
      security:
        - APIKeyHeader: []
components:
  schemas:
    CreateOrderPlainSchema:
      type: object
      title: CreateOrderPlainSchema
      description: Create order request body.
      required:
        - user_address
        - token
        - order_type
        - fiat_payload
      properties:
        user_address:
          type: string
          title: User Address
          description: >-
            Customer EVM address. For ONRAMP: receives the tokens. For OFFRAMP:
            spender address (must have ERC-20 allowance for the contract). If
            allowance is insufficient, the API returns 400
            `insufficient_allowance` with `data.required` and `data.current`.
        token:
          type: string
          title: Token
          description: >-
            ERC-20 token contract address (checksummed). Use `/meta/tokens` to
            discover supported tokens and addresses.
        order_type:
          $ref: '#/components/schemas/OrderType'
          description: Order direction. Integer enum (0=ONRAMP, 1=OFFRAMP).
        fiat_payload:
          $ref: '#/components/schemas/FiatPayload'
          description: >-
            Fiat configuration (amount, destination type, and destination
            details).
    OrderType:
      type: integer
      enum:
        - 0
        - 1
      title: OrderType
    FiatPayload:
      type: object
      title: FiatPayload
      required:
        - amount_fiat
        - cashout_type
      properties:
        amount_fiat:
          anyOf:
            - type: integer
            - type: number
          title: Amount Fiat
          description: Fiat amount in the selected currency (e.g., 1750).
        cashout_type:
          type: string
          enum:
            - PHONE
            - TILL
            - PAYBILL
            - BANK
          title: Cashout Type
          description: >-
            Destination type for the fiat leg. PHONE works for both on- and
            off-ramp; TILL/PAYBILL/BANK are off-ramp only.
        phone_number:
          anyOf:
            - type: string
            - type: 'null'
          title: Phone Number
          description: >-
            MSISDN in international format (e.g., +2547XXXXXXXX). Required when
            cashout_type=PHONE. For ONRAMP, receives STK push; for OFFRAMP,
            receives the payout. Also used for BANK transfers (mobile or account
            number).
        till_number:
          anyOf:
            - type: string
            - type: 'null'
          title: Till Number
          description: >-
            Buy Goods till number. Required when cashout_type=TILL. (OFFRAMP
            only.)
        paybill_number:
          anyOf:
            - type: string
            - type: 'null'
          title: Paybill Number
          description: >-
            PayBill business number. Required with account_number when
            cashout_type=PAYBILL. (OFFRAMP only.)
        account_number:
          anyOf:
            - type: string
            - type: 'null'
          title: Account Number
          description: >-
            Account number. Required for PAYBILL (with paybill_number) or BANK
            transfers.
        bank_code:
          anyOf:
            - type: string
            - type: 'null'
          title: Bank Code
          description: >-
            Bank code for bank transfers. Required when cashout_type=BANK. Use
            /api/v1/banks to get valid codes. (e.g., '0001' for KCB, '0068' for
            Equity)
        reference:
          anyOf:
            - type: string
            - type: 'null'
          title: Reference
          description: >-
            Free-form reference shown on the recipient/billing statement (e.g.,
            'INV-1024').
        currency:
          anyOf:
            - type: string
            - type: 'null'
          title: Currency
          default: KES
          description: >-
            ISO 4217 currency code for amount_fiat. Defaults to KES for now.
            Other currency will fail
        narrative:
          anyOf:
            - type: string
              maxLength: 120
            - type: 'null'
          title: Narrative
          description: Human-readable purpose for the payment (max 120 chars).
        client_ref:
          anyOf:
            - type: string
              maxLength: 64
            - type: 'null'
          title: Client Ref
          description: >-
            Merchant-defined reference (e.g., battery/device/store id). Max 64
            chars.
        metadata:
          anyOf:
            - type: object
              additionalProperties:
                type: string
                maxLength: 256
              maxProperties: 10
            - type: 'null'
          title: Metadata
          description: >-
            Additional merchant-defined metadata (e.g., device_id, batch_id).
            Supports up to 10 key/value pairs. Keys must be strings (max 64
            chars), values must be strings (max 256 chars).
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key

````