MagicPayments Integration Guides

General Card Gate

Pay-inPay-outCards

Accept card pay-ins on the MagicPayments hosted card form (no PCI scope on your side) and send card payouts.

When to use it

The General Card Gate accepts card pay-ins on the MagicPayments-hosted card form. The cardholder enters their PAN, expiry and CVV on our page — so the card data never touches your servers and your PCI scope stays minimal (SAQ-A). 3-D Secure, if required, is handled on the hosted page too. Use it for any card currency the gate supports (e.g. USD, EUR).

If you operate your own PCI-compliant card form and want to post raw card data yourself, use General Card H2H instead.

OperationRailHow the integration looks
Pay-inCard (hosted form)Create an invoice, redirect the cardholder to the hosted form.
Pay-outCardServer-to-server call to the card payout endpoint.
Prerequisites

Signing credentials from Getting started, a pay-in gate_id for the card gate, and a pay-out cascade_id enabled for card payouts.

Pay-in — hosted card form

  1. Create the invoice Call the gate endpoint with your gate_id, the amount and currency.
  2. Redirect the cardholder Send the browser to invoice_url. They enter card details and pass any 3-D Secure challenge on our page.
  3. Receive the result On completion we call your callback_url and redirect the browser to your return_success_url / return_decline_url.
POST/api/invoice
Request body
{
  "gate_id": "card-gate-eu",
  "invoice": {
    "invoice_id": "order-2026-000777",
    "currency": "EUR",
    "amount": 4999,
    "description": "Annual subscription",
    "ttl_minutes": 20
  },
  "customer": {
    "id": "cust-4451",
    "full_name": "Jane Subscriber",
    "email": "[email protected]"
  },
  "workflow_hooks": {
    "callback_url": "https://merchant.example.com/mp/callbacks",
    "return_success_url": "https://merchant.example.com/orders/777/thank-you",
    "return_decline_url": "https://merchant.example.com/orders/777/retry"
  }
}
Python
resp = signed_post("/api/invoice", {
    "gate_id": "card-gate-eu",
    "invoice": {
        "invoice_id": "order-2026-000777",
        "currency": "EUR",
        "amount": 4999,               # €49.99
        "description": "Annual subscription",
        "ttl_minutes": 20,
    },
    "customer": {
        "id": "cust-4451",
        "full_name": "Jane Subscriber",
        "email": "[email protected]",
    },
    "workflow_hooks": {
        "callback_url": "https://merchant.example.com/mp/callbacks",
        "return_success_url": "https://merchant.example.com/orders/777/thank-you",
        "return_decline_url": "https://merchant.example.com/orders/777/retry",
    },
})
redirect_url = resp.json()["invoice_url"]
Response
{
  "request_status": "success",
  "invoice_id": "1c3e5a90-7b21-4d6f-8a44-9e0c2b5d7f31",
  "merchant_invoice_id": "order-2026-000777",
  "invoice_status": "unpaid",
  "invoice_url": "https://stage.example-mp.com/public/invoice/1c3e5a90-.../gate",
  "message": "Invoice (Gate PayIn) with internal uid=1c3e5a90-... has been created."
}

Tracking the pay-in

POST/api/invoice/status
resp = signed_post("/api/invoice/status", {
    "merchant_invoice_id": "order-2026-000777"
})
invoice = resp.json()
# invoice["status"] -> "paid" | "payment_failed" | "declined_by_payer" | "expired"
# invoice["actual_payment"]["processing_info"]["amount_credited"] -> net to your wallet
Why the gate over H2H?

With the hosted form, sensitive card data and the 3-D Secure dance live entirely on our side. You get the smallest possible PCI footprint and don't have to build or certify a card-entry UI.

Pay-out — to a card

Card payouts (original credit transactions) go server-to-server. The destination is the card number; an expiry is included when the scheme requires it.

POST/api/payment/payout/card
Request body
{
  "cascade_id": "card-payout-eu",
  "payment": {
    "payment_id": "payout-2026-000045",
    "currency": "EUR",
    "amount": 15000,
    "description": "Affiliate payout May 2026"
  },
  "card": {
    "pan": "5555555555554444",
    "year": 2032,
    "month": 11,
    "card_holder": "ACME AFFILIATES"
  },
  "customer": {
    "id": "partner-2391",
    "full_name": "Acme Affiliates OÜ",
    "email": "[email protected]"
  },
  "workflow_hooks": {
    "callback_url": "https://merchant.example.com/mp/callbacks"
  }
}
Python
resp = signed_post("/api/payment/payout/card", {
    "cascade_id": "card-payout-eu",
    "payment": {
        "payment_id": "payout-2026-000045",
        "currency": "EUR",
        "amount": 15_000,             # €150.00
        "description": "Affiliate payout May 2026",
    },
    "card": {
        "pan": "5555555555554444",
        "year": 2032,
        "month": 11,
        "card_holder": "ACME AFFILIATES",
    },
    "customer": {"id": "partner-2391", "full_name": "Acme Affiliates OÜ"},
    "workflow_hooks": {"callback_url": "https://merchant.example.com/mp/callbacks"},
})
payout_uid = resp.json()["payment_id"]
Card payouts touch PCI scope

Sending a raw destination PAN means that request handles cardholder data, so it must run on a PCI-compliant backend over TLS — never from a browser or app. The hosted form keeps pay-ins out of scope, but a card payout by PAN is server-side by nature.

Tracking the pay-out

POST/api/payment/status
resp = signed_post("/api/payment/status", {
    "merchant_payment_id": "payout-2026-000045"
})
# resp.json()["status"] -> "success" | "processing" | "decline" | "error"

Testing & go-live