> For the complete documentation index, see [llms.txt](https://codemash.gitbook.io/codemash/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://codemash.gitbook.io/codemash/cloud/payments/integrations/providers/paypal.md).

# PayPal

Connect PayPal to Payments — keys, webhook URL and signing secret.

PayPal takes wallet and card payments and subscriptions. Norbix gets PayPal's webhook events (orders, captures, refunds, subscriptions, disputes).

## Get your credentials

1. Sign in to the [PayPal Developer Dashboard](https://developer.paypal.com/dashboard/) and choose **Sandbox** (tests) or **Live**.
2. Open **Apps & Credentials → Create App** and copy the **Client ID** and **Secret** (see [Get started with PayPal REST APIs](https://developer.paypal.com/api/rest/)).
3. Save the integration in Cloud once (below) to get its **Webhook URL**.
4. Open your app → **Add Webhook**, paste the webhook URL and select the events (see [Webhooks](https://developer.paypal.com/api/rest/webhooks/)). Copy the **Webhook ID** into Cloud, type the client secret again, and **Save**. PayPal signs every call with this id, so without it Norbix cannot accept the calls.

## Connect it in Cloud

**Where:** Payments → Integrations → **Add New Integration** → PayPal → **Connect** · `/projects/<project>/payments/integrations/new/paypal`

| Field            | Required | What it does                                                                                                          | Example             |
| ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------- | ------------------- |
| Client ID        | yes      | Your PayPal REST app.                                                                                                 | `AeA1…`             |
| Client Secret    | yes      | Lets Norbix call PayPal. Secret; encrypted on save and never shown again — type it again whenever you press **Save**. | `EC-…`              |
| Environment      | yes      | `sandbox` or `live` — type the word.                                                                                  | `sandbox`           |
| Webhook ID       | no       | The id of the PayPal webhook that points at the URL above — needed for payment triggers.                              | `8PT59735JN779430N` |
| Brand Name       | no       | Shown to buyers during PayPal checkout.                                                                               | `Acme Store`        |
| Integration Name | yes      | The name in your integrations list.                                                                                   | `PayPal sandbox`    |

<figure><img src="https://712692422-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHy372bqsaex2cqS3ikhL%2Fuploads%2Fgit-blob-27f5186e2bc43295e534ef5f18b980eac5e274d0%2Fpaypal-form-1.png?alt=media" alt="New PayPal Integration form filled with example values"><figcaption><p>The filled form (placeholder values).</p></figcaption></figure>

Press **Save**. The page turns into **Editing PayPal integration** with the badges **ENABLED**, **NOT TESTED**, **NOT CONFIRMED**, the integration id (`int_3GWTIFeBFBenGeyJ6raMjX`) and the **Webhook URL** — `<Hub address>/v3/payments/webhooks/<account id>/<project id>/paypal/<integration id>`; outside PROD it ends with `?env=<ENV>`. Copy it with its copy button and paste it at PayPal (see **Get your credentials**). **Received webhooks** at the bottom lists every call PayPal makes to it.

<figure><img src="https://712692422-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHy372bqsaex2cqS3ikhL%2Fuploads%2Fgit-blob-536c423b13493f57c48088d516b55e40302b97a8%2Fpaypal-saved-2.png?alt=media" alt="Editing PayPal integration after Save: ENABLED, NOT TESTED, NOT CONFIRMED, the integration id and the Webhook URL"><figcaption><p>After save: the webhook URL to paste at PayPal.</p></figcaption></figure>

Events Norbix accepts from PayPal (pick them at PayPal and in your [trigger](/codemash/cloud/payments/triggers/new.md)): `CHECKOUT.ORDER.APPROVED`, `PAYMENT.CAPTURE.COMPLETED`, `PAYMENT.CAPTURE.DENIED`, `PAYMENT.CAPTURE.REFUNDED`, `PAYMENT.SALE.COMPLETED`, `BILLING.SUBSCRIPTION.CREATED`, `BILLING.SUBSCRIPTION.CANCELLED`, `CUSTOMER.DISPUTE.CREATED`.

## Test and set as default

**Test integration** signs in to PayPal with the client id and secret. With the made-up values of this example it failed: *PayPal authentication failed for integration int\_3GWTIFeBFBenGeyJ6raMjX: HTTP 401 Unauthorized* (captured on [Test an integration](/codemash/cloud/payments/integrations/test.md)). Payments has no default integration — every enabled integration gets its own calls ([Default integration](/codemash/cloud/payments/integrations/set-default.md)).

## Common errors

| Message                                              | Cause                                                                          | Fix                                                                      |
| ---------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |
| PayPal authentication failed … HTTP 401 Unauthorized | Wrong client id or secret, or sandbox credentials with **Environment** `live`. | Copy both again from the same app and environment, **Save**, test again. |
| **Received webhooks** shows **400**                  | The **Webhook ID** is empty or belongs to another webhook.                     | Copy the id of the webhook that points at this URL and **Save**.         |
| Required                                             | A required field is empty — secrets count too on every save.                   | Fill the field; type every secret again before **Save**.                 |

## Do it from code

```ts
const { id } = await norbix.hub.payments.savePaymentsIntegration({
  integration: {
    provider: 'PayPal',
    integrationName: 'PayPal live',
    isEnabled: true,
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    environment: 'live',
    webhookId: '8PT59735JN779430N',
    brandName: 'Acme Store',
  } as any, // the TS type knows only the shared fields
});
console.log(id); // int_…
```

```sh
norbix hub payments integration save --integration '{"provider":"PayPal","integrationName":"PayPal live","isEnabled":true,"clientId":"your-client-id","clientSecret":"your-client-secret","environment":"live","webhookId":"8PT59735JN779430N","brandName":"Acme Store"}'
```

The client setup is on the [Payments page](/codemash/cloud/payments.md#use-it-from-code). API: [Save Payments Integration](/codemash/api-reference/payments/integrations/save-payments-integration.md)
