> ## Documentation Index
> Fetch the complete documentation index at: https://developers.hubspot.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Payments API (BETA)

> Create manual payment records and retry failed payments programmatically.

export const BetaDisclaimerBanner = () => <Warning>
        This functionality is currently in beta. By participating in this beta, you agree to HubSpot's <a href="https://legal.hubspot.com/developer-terms">Developer Terms</a> and <a href="https://legal.hubspot.com/developerbetaterms">Developer Beta Terms</a>. Note that the functionality is still under active development and is subject to change based on testing and feedback.
    </Warning>;

export const RequiredIndicator = () => {
  return <span className="required-indicator">
      required
    </span>;
};

export const ScopesList = ({scopes = [], description = "This API requires one of the following scopes:"}) => {
  if (!scopes || scopes.length === 0) {
    return null;
  }
  const sortedScopes = scopes.sort((a, b) => a.localeCompare(b));
  return <div>
      <div className="text-sm mb-2">{description}</div>
      <div>
        {sortedScopes.map((scope, index) => <div key={index}>
            <code>
              <span className="text-xs">{scope}</span>
            </code>
          </div>)}
      </div>
    </div>;
};

<Accordion title="Required scopes" icon="key">
  <ScopesList
    scopes={[
  'crm.objects.commercepayments.write',
  'crm.schemas.commercepayments.write'
]}
  />
</Accordion>

<BetaDisclaimerBanner />

Use the payments API to create manual payment records for transactions collected outside of HubSpot, and to retry failed payments without requiring manual action in the HubSpot UI. Both endpoints are available to any account with [HubSpot payments](https://knowledge.hubspot.com/payment-processing/set-up-payments) enabled.

## Create a manual payment

To create a manual payment record, make a `POST` request to `/commerce/payments/2027-03-beta/manual-payments`.

In the request body, you'll need to include `currencyCode`, `paymentAmount`, `paymentDate`, and `paymentMethod` at a minimum.

```json theme={null}
{
  "currencyCode": "USD",
  "paymentAmount": 1500.00,
  "paymentDate": "2026-09-10T00:00:00Z",
  "paymentMethod": "CHECK",
  "customerEmail": "customer@example.com",
  "billingAddress": {
    "line1": "123 Main St",
    "city": "Cambridge",
    "state": "MA",
    "postalCode": "02139",
    "country": "US"
  }
}
```

| Parameter                             | Type   | Description                                                                                                                                             |
| ------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `currencyCode` <RequiredIndicator />  | String | The currency code for the payment (e.g., `USD`).                                                                                                        |
| `paymentAmount` <RequiredIndicator /> | Number | The total amount of the payment.                                                                                                                        |
| `paymentDate` <RequiredIndicator />   | String | The date of the payment in ISO-8601 instant format (e.g., `2026-09-10T00:00:00Z`).                                                                      |
| `paymentMethod` <RequiredIndicator /> | String | The method used for the payment. Accepted values: `CASH`, `CHECK`, `WIRE_TRANSFER`, `CARD`, `ACH`, `SEPA`, `BACS`, `PADS`, `KLARNA`, `AFFIRM`, `OTHER`. |
| `customerEmail`                       | String | The email address of the customer associated with the payment.                                                                                          |
| `billingAddress`                      | Object | The billing address for the payment. Accepts `line1`, `line2`, `city`, `state`, `postalCode`, and `country`.                                            |

When the request is successful, the response returns the `id` of the newly created payment record.

### Associations

To associate the payment with other CRM records on creation, you can include the `associations` array in the create request body to define each association.

```json highlight={14-27} theme={null}
{
  "currencyCode": "USD",
  "paymentAmount": 1500.00,
  "paymentDate": "2026-09-10T00:00:00Z",
  "paymentMethod": "CHECK",
  "customerEmail": "customer@example.com",
  "billingAddress": {
    "line1": "123 Main St",
    "city": "Cambridge",
    "state": "MA",
    "postalCode": "02139",
    "country": "US"
  },
  "associations": [
    {
      "to": {
        "id": "12345",
        "objectType": "0-1"
      },
      "types": [
        {
          "associationCategory": "HUBSPOT_DEFINED",
          "associationTypeId": 387
        }
      ]
    }
  ]
}
```

| Parameter                     | Type   | Description                                                                                                                         |
| ----------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| `to.id`                       | String | The ID of the target CRM record to associate with the payment.                                                                      |
| `to.objectType`               | String | The target object type in `metaTypeId-innerId` format (e.g., `0-1` for contacts). Supported object types are listed below.          |
| `types[].associationCategory` | String | The association category. Use `HUBSPOT_DEFINED` for standard HubSpot association types.                                             |
| `types[].associationTypeId`   | Number | The association type ID that defines the relationship between the payment and the target object. Supported values are listed below. |

Supported associations for payments include:

| Target object | `to.objectType` | `associationTypeId` |
| ------------- | --------------- | ------------------- |
| Contact       | `0-1`           | `387`               |
| Company       | `0-2`           | `389`               |
| Deal          | `0-3`           | `391`               |
| Subscription  | `0-69`          | `393`               |
| Line item     | `0-8`           | `395`               |
| Quote         | `0-14`          | `397`               |
| Invoice       | `0-53`          | `542`               |

## Retry a failed payment

The retry endpoint uses an asynchronous pattern: you initiate the retry with a `POST` request, which returns a task ID, then poll a separate status endpoint to check the result.

### Initiate a retry

To initiate a retry, make a `POST` request to `/commerce/payments/2027-03-beta/{paymentCrmObjectId}/actions/retry/async`, where `{paymentCrmObjectId}` is the ID of the payment CRM object you want to retry.

A successful request returns a `202` response containing a `TaskLocator` object with the `id` of the retry task.

### Check retry status

To check the status of a retry, make a `GET` request to `/commerce/payments/2027-03-beta/{paymentCrmObjectId}/actions/retry/async/tasks/{taskId}/status`, using the `taskId` value returned from the initiate request.

The response includes a `status` field with one of the following values:

| Status       | Description                                        |
| ------------ | -------------------------------------------------- |
| `PENDING`    | The retry has been queued and has not yet started. |
| `PROCESSING` | The retry is currently in progress.                |
| `COMPLETE`   | The retry completed successfully.                  |
| `CANCELED`   | The retry was canceled before completing.          |

The response also includes `startedAt`, `completedAt`, and, if any errors occurred, an `errors` array and `numErrors` count.
