ElebneElebneDocs
Pay API

Payment Intents

Create, retrieve, list, and cancel payment intents. Understand the full lifecycle from creation to settlement.

Payment Intents

A payment intent represents a single payment request. It tracks the full lifecycle from creation through payment, and optionally through refund.

Status flow

PENDING ──────> PAID ──────> REFUNDED

   ├──────> CANCELLED  (merchant cancel or 24h expiry)

   └──────> FAILED     (payment error)
  • PENDING -- intent created, waiting for customer payment
  • PAID -- customer has paid, funds are in your merchant account
  • REFUNDED -- one or more refunds have been issued
  • CANCELLED -- cancelled by merchant or expired after 24 hours
  • FAILED -- payment attempt failed

Create an intent

Idempotency required

All write endpoints require an X-Idempotency-Key header. Use a unique key per request (e.g. your order ID). Safe to retry on network errors.

POST /dev/intents

Request body

FieldTypeRequiredDescription
amountintegerYesAmount in centimes. 50000 = 500.00 MRU. Minimum: 1 centime.
amountTypestringNoFIXED (default) or OPEN. Open lets customer choose amount.
labelstringNoDescription shown to customer. Max 200 characters.
metadataobjectNoKey-value pairs (string values only). Max 50 keys, 500 chars per value.
success_urlstringNoURL to redirect customer after payment (for Hosted Checkout).
cancel_urlstringNoURL to redirect customer on cancellation.

Response

FieldTypeDescription
referenceNumberstringUnique identifier, e.g. PI-3XXXXXXXXXXXXXX
shortCodestring6-character alphanumeric code for short URLs
codestring6-digit payment code for in-person payments
codeExpiresAtstringISO 8601 expiration time for the payment code
payUrlstringHosted Checkout URL: https://pay.elebne.ai/p/{shortCode}
amountintegerAmount in centimes (null for OPEN intents)
amountTypestringFIXED or OPEN
currencystringAlways MRU
labelstringPayment description
statusstringPENDING
sandboxbooleantrue for test keys, false for live
metadataobjectYour custom key-value pairs
expiresAtstringISO 8601 expiration (24h from creation)
createdAtstringISO 8601 creation timestamp
curl -X POST https://api.elebne.ai/api/v1/dev/intents \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: order-5678" \
  -d '{
    "amount": 50000,
    "label": "Abonnement mensuel",
    "metadata": {
      "customer_id": "cust_001",
      "plan": "premium"
    }
  }'
const response = await fetch('https://api.elebne.ai/api/v1/dev/intents', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_test_YOUR_KEY',
    'Content-Type': 'application/json',
    'X-Idempotency-Key': 'order-5678',
  },
  body: JSON.stringify({
    amount: 50000,
    label: 'Abonnement mensuel',
    metadata: {
      customer_id: 'cust_001',
      plan: 'premium',
    },
  }),
});

const { data } = await response.json();
console.log(data.referenceNumber); // PI-3XXXXXXXXXXXXXX
console.log(data.code);            // 482917
console.log(data.payUrl);          // https://pay.elebne.ai/p/A1B2C3
import requests

response = requests.post(
    'https://api.elebne.ai/api/v1/dev/intents',
    headers={
        'Authorization': 'Bearer sk_test_YOUR_KEY',
        'Content-Type': 'application/json',
        'X-Idempotency-Key': 'order-5678',
    },
    json={
        'amount': 50000,
        'label': 'Abonnement mensuel',
        'metadata': {
            'customer_id': 'cust_001',
            'plan': 'premium',
        },
    },
)

data = response.json()['data']
print(data['referenceNumber'])  # PI-3XXXXXXXXXXXXXX
print(data['code'])             # 482917
print(data['payUrl'])           # https://pay.elebne.ai/p/A1B2C3

Get an intent

Retrieve the current state of a payment intent. Use this to verify payment status after a redirect or webhook.

GET /dev/intents/{referenceNumber}

Read-only endpoint

You can use either your secret key or publishable key for this endpoint.

curl https://api.elebne.ai/api/v1/dev/intents/PI-3XXXXXXXXXXXXXX \
  -H "Authorization: Bearer pk_test_YOUR_KEY"
const response = await fetch(
  'https://api.elebne.ai/api/v1/dev/intents/PI-3XXXXXXXXXXXXXX',
  {
    headers: { 'Authorization': 'Bearer pk_test_YOUR_KEY' },
  }
);

const { data } = await response.json();
console.log(data.status);   // PAID
console.log(data.payment);  // { amountPaid: 50000, paidAt: "...", method: "WALLET" }
response = requests.get(
    'https://api.elebne.ai/api/v1/dev/intents/PI-3XXXXXXXXXXXXXX',
    headers={'Authorization': 'Bearer pk_test_YOUR_KEY'},
)

data = response.json()['data']
print(data['status'])   # PAID
print(data['payment'])  # { amountPaid: 50000, paidAt: "...", method: "WALLET" }

Response for a paid intent:

{
  "success": true,
  "data": {
    "referenceNumber": "PI-3XXXXXXXXXXXXXX",
    "shortCode": "A1B2C3",
    "type": "API",
    "amount": 50000,
    "amountType": "FIXED",
    "currency": "MRU",
    "label": "Abonnement mensuel",
    "status": "PAID",
    "sandbox": true,
    "metadata": { "customer_id": "cust_001", "plan": "premium" },
    "payment": {
      "amountPaid": 50000,
      "paidAt": "2026-04-04T10:35:00.000Z",
      "method": "WALLET"
    },
    "refunds": [],
    "totalAmountRefunded": 0,
    "expiresAt": "2026-04-05T10:30:00.000Z",
    "createdAt": "2026-04-04T10:30:00.000Z",
    "updatedAt": "2026-04-04T10:35:00.000Z"
  }
}

List intents

Retrieve a paginated list of your payment intents with optional filters.

GET /dev/intents?status=PAID&page=1&limit=20&from=2026-01-01&to=2026-12-31
ParameterTypeDefaultDescription
statusstringallFilter by status: PENDING, PAID, REFUNDED, CANCELLED, FAILED
fromstring--ISO 8601 date, inclusive start
tostring--ISO 8601 date, inclusive end
pageinteger1Page number (starts at 1)
limitinteger20Results per page (max 100)
curl "https://api.elebne.ai/api/v1/dev/intents?status=PAID&page=1&limit=10" \
  -H "Authorization: Bearer sk_test_YOUR_KEY"
const params = new URLSearchParams({
  status: 'PAID',
  page: '1',
  limit: '10',
});

const response = await fetch(
  `https://api.elebne.ai/api/v1/dev/intents?${params}`,
  {
    headers: { 'Authorization': 'Bearer sk_test_YOUR_KEY' },
  }
);

const { data } = await response.json();
console.log(`${data.total} paid intents`);
response = requests.get(
    'https://api.elebne.ai/api/v1/dev/intents',
    headers={'Authorization': 'Bearer sk_test_YOUR_KEY'},
    params={'status': 'PAID', 'page': 1, 'limit': 10},
)

result = response.json()
print(f"{result['data']['total']} paid intents")

Response:

{
  "success": true,
  "data": {
    "items": [
      { "referenceNumber": "PI-3XXXXXXXXXXXXXX", "amount": 50000, "status": "PAID", "..." : "..." }
    ],
    "page": 1,
    "limit": 10,
    "total": 42,
    "hasMore": true
  }
}

Cancel an intent

Cancel a pending payment intent. Only intents with status PENDING can be cancelled.

POST /dev/intents/{referenceNumber}/cancel
curl -X POST https://api.elebne.ai/api/v1/dev/intents/PI-3XXXXXXXXXXXXXX/cancel \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "X-Idempotency-Key: cancel-order-5678"
const response = await fetch(
  'https://api.elebne.ai/api/v1/dev/intents/PI-3XXXXXXXXXXXXXX/cancel',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_test_YOUR_KEY',
      'X-Idempotency-Key': 'cancel-order-5678',
    },
  }
);

const { data } = await response.json();
console.log(data.status); // CANCELLED
response = requests.post(
    'https://api.elebne.ai/api/v1/dev/intents/PI-3XXXXXXXXXXXXXX/cancel',
    headers={
        'Authorization': 'Bearer sk_test_YOUR_KEY',
        'X-Idempotency-Key': 'cancel-order-5678',
    },
)

data = response.json()
print(data['status'])  # CANCELLED

Expiration

Unpaid intents automatically expire 24 hours after creation. When an intent expires:

  1. Status changes from PENDING to CANCELLED
  2. A payment.expired webhook event is fired
  3. The 6-digit payment code is released

You do not need to manually cancel expired intents.

Error responses

Error codeHTTPDescription
IDEMPOTENCY_KEY_REQUIRED400Missing X-Idempotency-Key header
AMOUNT_OUT_OF_RANGE400Amount outside allowed limits
METADATA_TOO_MANY_KEYS400Metadata has more than 50 keys
METADATA_VALUE_TOO_LONG400A metadata value exceeds 500 characters
INTENT_NOT_FOUND404Intent does not exist or belongs to another business
INTENT_CANCEL_INVALID_STATUS400Intent is not in PENDING status
INTENT_CANCEL_CONFLICT400Intent status changed concurrently

Next steps

Was this page helpful?

On this page