Skip to content

Step 4: Create Payment

Create one collection attempt for an unpaid order, using the customer-confirmed total.

Before creating a payment

Call Calculate Order before each new payment attempt and confirm the returned total with the customer. This picks up changes to fees or the selected payment method. Send that total as expected_payment_total.

Endpoint

http
POST https://api.iimmpact.com/v2/payments

Request headers

FieldTypeRequiredDescription
X-Api-KeystringYesYour API key; keep it on your backend.
X-TimestampstringYesCurrent Unix time in seconds; within five minutes of server time.
X-NoncestringYesFresh identifier for every request, including retries.
X-SignaturestringYesv1= followed by the request's HMAC signature.

Follow API Key Authentication. Sign the exact body, or an empty body for bodyless requests, and the sorted query when present.

FieldTypeRequiredDescription
Content-TypestringYesapplication/json.
Idempotency-KeystringYesUnique attempt key; network retries reuse the admitted key.

Request fields

FieldTypeRequiredDescription
order_idstringYesExisting unpaid order, with no pending or unresolved payment.
customer_external_idstringYesYour own customer ID as a non-empty string, matching the method lookup. No particular ID format is required.
payment_method_codestringYesCode from Payment Methods.
return_urlstringYesYour HTTPS destination after checkout or authentication. See restrictions below.
expected_payment_totalstringYesPositive two-place MYR total confirmed by the customer.
customer_fee_percentstringNoPercentage of the fee the customer bears, 0.00100.00; defaults to 0.00 on each request.
saved_payment_method_idstringNoSaved option for this customer and method within your account. Mutually exclusive with card_details.
save_payment_methodbooleanNoRequest saving with customer consent; defaults to false. Currently supported for hosted new cards. Cannot be true with a saved method ID.
card_detailsobjectConditionalRequired for approved direct card entry; omitted for hosted entry and saved methods.

return_url cannot contain userinfo, fragments, local/private destinations, or existing order_id/payment_id query keys, including encoded or case-insensitive variants. Other safe query parameters are retained. Use a destination you control and authorize order access on your backend.

Choose payment input

ChoiceSendCustomer action
Hosted checkoutNeither card_details nor saved_payment_method_idComplete the selected method's checkout.
Save a hosted new cardsave_payment_method: true, with customer consentComplete checkout; refresh methods after saving succeeds.
Saved payment methodsaved_payment_method_idComplete any required authentication.
Direct new cardcard_details, only when enabledEnter details in your UI, then complete any required 3DS.

Select a saved ID returned for the same customer and method. Unavailable or inaccessible IDs return validation_error. card_details is only for cards; unsupported saving requests are rejected. Requesting saving does not guarantee it has completed.

Request example — hosted card

json
{
  "order_id": "ord_example",
  "customer_external_id": "CUS-1042",
  "payment_method_code": "CARD",
  "return_url": "https://shop.example.com/payment-return",
  "customer_fee_percent": "50.00",
  "expected_payment_total": "100.85"
}

For a saved payment method, add its ID to the same request:

json
{
  "saved_payment_method_id": "spm_example"
}

Direct card entry

Activation required

Direct full-PAN entry is a proposed, gated capability. It requires PCI-DSS Level 1 compliance and account approval; Malaysia/MYR availability and the recovery protocol must be confirmed before use. Direct-card saving is not yet supported by this contract.

Your card form sends input through your backend → IIMMPACT. Keep API/HMAC credentials off the browser. Systems handling card input are in PCI scope: never log or durably store card_details, including in retry queues or request capture. Never retain CVV after authorization.

These are the proposed required fields within card_details, subject to activation validation:

FieldTypeRequiredDescription
card_numberstringYesFull PAN, digits only.
expiry_monthstringYesTwo-digit month, 0112.
expiry_yearstringYesFour-digit year; card must be unexpired.
cvvstringYesCard security code, digits only.
cardholder_first_namestringYesCardholder's first name.
cardholder_last_namestringYesCardholder's last name.
cardholder_emailstringYesValid cardholder email.

Direct-entry request example with a documentation test card, not live card data:

json
{
  "order_id": "ord_example",
  "customer_external_id": "CUS-1042",
  "payment_method_code": "CARD",
  "return_url": "https://shop.example.com/payment-return",
  "customer_fee_percent": "50.00",
  "expected_payment_total": "100.85",
  "card_details": {
    "card_number": "4000000000001091",
    "expiry_month": "12",
    "expiry_year": "2029",
    "cvv": "123",
    "cardholder_first_name": "Amira",
    "cardholder_last_name": "Hassan",
    "cardholder_email": "amira@example.com"
  }
}

Recovery: retain safe references and any returned payment ID, not the raw card request. Read a known payment after uncertainty; do not start another attempt or blindly resubmit card data. If the response is lost before an ID is received, the creation-key recovery protocol must be agreed during activation. Permanent replay must return the admitted attempt without storing CVV or initiating another collection; this guide does not yet prescribe a runnable recovery request for that case.

Response fields

Fields below are inside data.

FieldTypeDescription
payment_idstringSave for status checks.
order_idstringOrder being paid.
external_referencestringYour order reference.
customer_external_idstringPayer identity for this attempt.
statusstringCurrent collection state.
currencystringMYR.
payment_method_codestringSelected method.
customer_fee_percentstringAdmitted percentage of the fee the customer bears, 0.00100.00.
feeobjectAdmitted fee rule.
totalsobjectFrozen amount breakdown.
actionobject or nullCurrent redirect action; null when none is usable. Omitted from webhook snapshots.
action.typestringredirect, when action exists.
action.urlstringHTTPS checkout or 3DS URL, when action exists.
failureobjectReturned only for failed; omitted otherwise.
failure.codestringFailure code, e.g. collection_failed, when failure exists.
failure.messagestringSafe display text, when failure exists.
created_atstringRFC3339 payment creation time.
updated_atstringRFC3339 time of the latest public payment change.

Card input and return destinations are never echoed. Fulfillment and refunds are on the order. A successful collection remains successful after a refund.

Response example — 201

json
{
  "data": {
    "payment_id": "pay_example",
    "order_id": "ord_example",
    "external_reference": "ORD-00042",
    "customer_external_id": "CUS-1042",
    "status": "pending",
    "currency": "MYR",
    "payment_method_code": "CARD",
    "customer_fee_percent": "50.00",
    "fee": {
      "type": "percentage",
      "value": "1.70"
    },
    "totals": {
      "items_subtotal": "100.00",
      "fee": {
        "total": "1.70",
        "customer": "0.85",
        "merchant": "0.85"
      },
      "payment_total": "100.85"
    },
    "action": {
      "type": "redirect",
      "url": "https://payments.example/checkout/session"
    },
    "created_at": "2026-09-14T10:05:00+08:00",
    "updated_at": "2026-09-14T10:05:00+08:00"
  }
}

If initiation is uncertain, HTTP 202 returns the same schema with status: "processing" and action: null. Keep the payment ID and await an event or read; do not create a replacement.

Redirect and browser return

Follow the current action.url when present. It can open hosted checkout or 3DS authentication. When action is null, use the status to decide whether to wait or show the result.

After checkout/authentication, the browser returns to this payment's return_url with order_id and payment_id. Those IDs are not authorization or proof of payment. Authenticate the customer and read current payment/order state.

Errors

HTTPCodeAction
400idempotency_key_requiredSupply the attempt key.
404order_not_foundCheck the order ID and access.
409order_already_paidRead the existing order; latest_payment_id identifies the winning collection. Do not charge again.
409payment_outcome_unresolvedWait for the existing attempt's outcome. Read latest_payment_id from the order, then check that payment's status.
409idempotency_conflictThis key was already used with different request data. Check the existing payment before starting a new attempt.
409total_mismatchNo payment created; confirm the fresh calculation below.
422validation_errorCorrect field errors, such as an unavailable saved method or an invalid fee percent.
422payment_method_unavailableRefresh methods and choose an available one.

See shared errors.

Total mismatch fields

FieldTypeDescription
error.details.expected_payment_totalstringThe total you submitted.
error.details.calculationobjectFull existing-order calculation: quote fields plus order_id.

Show the new calculation.totals.payment_total and obtain confirmation before submitting a corrected request with a new key.

Cancel a payment

http
POST https://api.iimmpact.com/v2/payments/{payment_id}/cancel

Use the same authentication headers, signing an empty body.

Path fields

FieldTypeRequiredDescription
payment_idstringYesYour eligible pending payment. Successful collections cannot be cancelled.

Request example

bash
curl --request POST "https://api.iimmpact.com/v2/payments/$PAYMENT_ID/cancel" \
  --header "X-Api-Key: $API_KEY" \
  --header "X-Timestamp: $TIMESTAMP" \
  --header "X-Nonce: $NONCE" \
  --header "X-Signature: v1=$SIGNATURE"

Response fields

FieldTypeDescription
data.payment_idstringPayment being cancelled.
data.order_idstringRelated order.
data.external_referencestringYour order reference.
data.statusstringcancelled (200) or cancellation_pending (202).
data.created_atstringRFC3339 payment creation time.
data.updated_atstringRFC3339 latest payment change.

Response example — 200

json
{
  "data": {
    "payment_id": "pay_example",
    "order_id": "ord_example",
    "external_reference": "ORD-00042",
    "status": "cancelled",
    "created_at": "2026-09-14T10:05:00+08:00",
    "updated_at": "2026-09-14T10:06:00+08:00"
  }
}

Repeated calls return the existing cancellation result without resubmitting cancellation. Wait for a final outcome before retrying payment; collection can win a cancellation race.

HTTPCodeMeaning
404payment_not_foundMissing or inaccessible payment.
409payment_already_successfulCollection succeeded; cancellation cannot refund it.
409payment_outcome_unresolvedCollection is still uncertain.
409payment_already_terminalAlready failed or expired.
409cancellation_not_supportedThis payment cannot be cancelled.
422validation_errorInvalid payment ID.

Collection lifecycle and conflicts

StatusMeaning
pendingWaiting for customer action; blocks another attempt.
processingInitiation or collection is unresolved; blocks another attempt.
cancellation_pendingCancellation is unresolved; blocks another attempt.
successfulCollection verified.
failed, cancelled, expiredConfirmed unsuccessful outcome; a new attempt may be eligible.

See expiry and retry rules. Next: Track Results.

Refunds

IIMMPACT handles refunds for failed fulfillment and duplicate collections. See Refunds for amounts and progress; refund data is returned on the order.

IIMMPACT API Documentation