# Card payments

Take Visa and Mastercard payments on a hosted checkout page. You send the payment, Payd returns a checkout link, and your customer pays on that page.

<div class="endpoint"><span class="method post">POST</span><code>https://api.payd.money/api/v2/payments/payin</code></div>

::: tip Switch card payments on first
Card payments are off until Payd turns them on for your account. Email [support@paydhq.com](mailto:support@paydhq.com) with your account id. Until then, card requests return `403` `permission_denied`.
:::

## How it works

1. You send the payin with `transaction_channel` set to `card`.
2. Payd returns a `checkout_url`. Send the customer there.
3. The customer pays on the checkout page and returns to your `redirect_url`.
4. Payd posts a webhook with `status` `success`.
5. Payd holds card money for 72 hours in case of a chargeback, then releases it to your balance and posts a second webhook, `payin.settled`, with `status` `settled`.

## Request

::: code-group

```bash [cURL]
curl https://api.payd.money/api/v2/payments/payin \
  -u "$PAYD_API_USERNAME:$PAYD_API_PASSWORD" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 2500,
    "currency": "KES",
    "transaction_channel": "card",
    "customer": {
      "first_name": "Amina",
      "last_name": "Wanjiru",
      "email": "amina@example.com",
      "phone_number": "254712345678"
    },
    "vendor_config": { "account_id": "4f28836c-2f1e-4d9b-9a51-6f3c2b1d8e70" },
    "provider_config": {},
    "payment_config": {
      "remark": "Order 8842",
      "reference": "order-8842",
      "callback_url": "https://example.com/webhooks/payd"
    },
    "redirect_url": "https://example.com/orders/8842/paid"
  }'
```

```js [Node.js]
const auth = Buffer.from(
  `${process.env.PAYD_API_USERNAME}:${process.env.PAYD_API_PASSWORD}`,
).toString('base64')

const res = await fetch('https://api.payd.money/api/v2/payments/payin', {
  method: 'POST',
  headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    amount: 2500,
    currency: 'KES',
    transaction_channel: 'card',
    customer: {
      first_name: 'Amina',
      last_name: 'Wanjiru',
      email: 'amina@example.com',
      phone_number: '254712345678',
    },
    vendor_config: { account_id: process.env.PAYD_ACCOUNT_ID },
    provider_config: {},
    payment_config: {
      reference: 'order-8842',
      callback_url: 'https://example.com/webhooks/payd',
    },
    redirect_url: 'https://example.com/orders/8842/paid',
  }),
  signal: AbortSignal.timeout(35_000),
})
const { gateway_response: payment } = await res.json()

// Save payment.merchant_reference with the order, then send the customer to pay
return Response.redirect(payment.checkout_url, 303)
```

```python [Python]
import os
import requests

res = requests.post(
    "https://api.payd.money/api/v2/payments/payin",
    auth=(os.environ["PAYD_API_USERNAME"], os.environ["PAYD_API_PASSWORD"]),
    json={
        "amount": 2500,
        "currency": "KES",
        "transaction_channel": "card",
        "customer": {
            "first_name": "Amina",
            "last_name": "Wanjiru",
            "email": "amina@example.com",
            "phone_number": "254712345678",
        },
        "vendor_config": {"account_id": os.environ["PAYD_ACCOUNT_ID"]},
        "provider_config": {},
        "payment_config": {"reference": "order-8842", "callback_url": "https://example.com/webhooks/payd"},
        "redirect_url": "https://example.com/orders/8842/paid",
    },
    timeout=35,
)
res.raise_for_status()
payment = res.json()["gateway_response"]
# Save payment["merchant_reference"] with the order, then redirect to payment["checkout_url"]
```

:::

### Fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `amount` | number | Yes | Amount to charge. |
| `currency` | string | Yes | Currency to charge in. Payd confirms which currencies your account can charge when it turns card payments on. |
| `transaction_channel` | string | Yes | `card`. |
| `customer.first_name`, `customer.last_name` | string | Yes | Cardholder's name. |
| `customer.email` | string | Yes | Cardholder's email. The checkout page uses it for the receipt. |
| `customer.phone_number` | string | Yes | Cardholder's phone number in international form. |
| `vendor_config.account_id` | string | Yes | Your [account id](./authentication.md#find-your-account-id). |
| `provider_config` | object | Yes | Send `{}`. |
| `payment_config.reference` | string | No | Your own id for the payment. |
| `payment_config.callback_url` | string | No | Where Payd posts the result. |
| `redirect_url` | string | No | Where the checkout page sends the customer after they pay. |

## Response

```json
{
  "gateway_response": {
    "success": true,
    "merchant_reference": "9BD103512274eR",
    "checkout_url": "https://checkout.example/pay/7c1e9a52"
  }
}
```

Send the customer to `checkout_url`, in the same tab or a new one.

## When the customer comes back

The checkout page sends the customer to your `redirect_url` with some query parameters added. Do not trust the visit itself: anyone can open that URL. Look up the order's `merchant_reference` and check the [status](./transaction-status.md) before you show "Payment received".

## Settlement

| Webhook `status` | Meaning | Your balance |
| --- | --- | --- |
| `success` | The card was charged. | The amount shows as `inflight_balance` on the [balances endpoint](./balances.md). |
| `settled` | Payd released the money. | The amount moves to your available balance. |

You can ship once the payment is `success`. The hold only affects when you can pay the money out.
