# Create your first draft payment

To use our draft payments endpoint, you must register your application and request an approval in the [Developer Portal](https://developer.revolut.com/portal/applications).

Before you begin, ensure that you have:

- Registered your application with the `draftpayments` in Developer Portal
- Obtained a sandbox/production `client_id`  from Developer Portal
- Obtained a sandbox/production `transport.pem` certificate from Developer Portal

:::tip
The draft payment function is available only for Revolut Business customers.
:::

:::warning
If you get certificate errors when using `curl` with Sandbox, it usually means your system [doesn't trust our certificate issuer](/docs/guides/build-banking-apps/get-started/get-access-token#certificates). The recommended approach is to add the certificate to your trusted store.

As a quick workaround, you can use the `-k` (or `--insecure`) option to skip certificate checks. **Be aware this disables all SSL verification, which can hide issues like expired or mismatched certificates and leaves you vulnerable to man-in-the-middle attacks**. For these reasons, avoid using `-k` in production or as a permanent solution.
:::

## 1. Get user's authorization

- ```shell [Production]
  https://business.revolut.com/partner-confirm?response_type=code&state=state&scope=draftpayments&client_id=<your client_id>&redirect_uri=<your redirect_uri>
  ```

- ```shell [Sandbox]
  https://sandbox-business.revolut.com/partner-confirm?response_type=code&state=state&scope=draftpayments&client_id=<your client_id>&redirect_uri=<your redirect_uri>
  ```

Response would look like this: 

```shell
https://www.revolut_redirect.com/revolut_redirect?code=oa_sand_kiLg3m7xrNua0rbShC1GQZfbk0DthUhOpVA9xX2oRY0&state=state
```

Before you can start creating draft payments, you must get authorization from the user to make draft payments on their behalf.

Redirect the user to the authorization URL with the following parameters.

| Parameter       | Description                                                                                                                                                                                     | Required |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `scope`         | The scope for authorization required from the user.                                                                                                                                             | yes      |
| `client_id`     | The client ID for your application.                                                                                                                                                             | yes      |
| `redirect_uri`  | One of the redirect URIs that you defined when you created the application. Keep it static without variable parameters (`https://example.com`).                                                 | yes      |
| `state`         | The generated string to verify the response is initiated by the same user.                                                                                                                      | yes      |
| `response_mode` | If set to `fragment` parameters will be passed in fragment section of redirect URI. Otherwise, parameters are passed in URI query. Passing parameters in fragment considered to be more secure. | no       |

On successful completion of the authorization flow, you receive an authorization code (`code`).

A sample response code might look like this:

```
oa_sand_aa1ZYnWWMj3Y2NgzSw1EIqfJQJ7YOG3aPV2WHa-sQOx
```

:::warning
The `code` is valid only for two minutes.
:::

## 2. Exchange authorization code for access token

Token request via MTLS:

- ```shell [Production]
  curl --key private.key --cert transport.pem \
  --location --request POST 'https://oba-auth.revolut.com/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=<your client_id>' \
  --data-urlencode 'code=<insert authorization_code>'
  ```

- ```shell [Sandbox]
  curl --key private.key --cert transport.pem \
  --location --request POST 'https://sandbox-oba-auth.revolut.com/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=<your client_id>' \
  --data-urlencode 'code=<insert authorization_code>'
  ```

MTLS response:

```json
{
  "access_token":"oa_prod_uuWhyiJt1oSoE6aeSxVO8ZpuR_VtgrgPllZKSvHoQ-I",
  "refresh_token":"oa_prod_tUf_3gZJA6vNH4AnBMVEPqbykkfgBomWwDGRo8tBThA",
  "access_token_id":"3d3ef8a1-f920-4d6d-9106-e7fcf350125c",
  "token_type":"Bearer",
  "expires_in":7775999
}
```

- `access_token` is the access token you received.
- `expires_in` is the time duration in seconds that the token is valid for. An access token is valid for 90 days. Before it expires, you must refresh the access token. For more information, see: [Tutorials: Create your first draft payment - Refresh access token](/docs/guides/build-banking-apps/tutorials/create-your-first-draft-payment#3-refresh-access-token).
- `access_token_id` is used in conjunction with the `token` webhook to identify tokens where the user has revoked their consent.

Exchange your authorization code for an access token using the token endpoint.

## 3. Refresh access token

Refresh access token:

- ```shell [Production]
  curl --key private.key --cert transport.pem \
  --location --request POST 'https://oba-auth.revolut.com/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'refresh_token=<insert refresh_token>'
  ```

- ```shell [Sandbox]
  curl --key private.key --cert transport.pem \
  --location --request POST 'https://sandbox-oba-auth.revolut.com/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'refresh_token=<insert refresh_token>'
  ```

Response:

```json
{
  "access_token":"oa_prod_h_M1nWyehXEkx3kF1QhEoqksQT0NaYKfBuEEBv1dSOY",
  "token_type":"Bearer",
  "expires_in":7775999
}
```

Each access token is valid for 90 days. When it expires, you must refresh the access token before you create a draft payment.

To do that, use the `refresh_token` returned in the previous step to request a new access token that can be used for a further 90 days.

## 4. Create a draft payment

Create a draft payment:

- ```shell [Production]
  curl --location --request POST 'https://apis.revolut.com/draft-payments' \
  --header 'Authorization: Bearer <insert access_token>' \
  --header 'x-idempotency-key: 2c199c8c-671f-11eb-ae93-0242ac130002' \
  --header 'Content-Type: text/csv' \
  --data-binary @draft_payments.csv
  ```

- ```shell [Sandbox]
  curl --location --request POST 'https://sandbox-apis.revolut.com/draft-payments' \
  --header 'Authorization: Bearer <insert access_token>' \
  --header 'x-idempotency-key: 2c199c8c-671f-11eb-ae93-0242ac130002' \
  --header 'Content-Type: text/csv' \
  --data-binary @draft_payments.csv
  ```

Response:

```json
{"DraftPaymentId":"4bc0a477-2c81-4f49-bf5b-c6705bb7a6d9"}
```

After you have an access token, you can use the `/draft-payments` endpoint to create a draft payment on behalf of the user. Include a CSV file with the supported format shown in the following tables and a unique `idempotency-key` of `uuid` format.

After you create the draft payment, it appears in the user's Revolut Business account where user can approve or reject.

:::warning
The maximum number of rows in a CSV file is 50 and all the payments must be in the same currency.
:::

For information about which fields are required based on the country and the currency, see: [Tutorials: Work with draft payments - International payments](/docs/guides/build-banking-apps/tutorials/work-with-draft-payments#international-payments).

### Parameters

| Name            | Located in | Description                                                                                                           | Required | Schema                      |
| --------------- | ---------- | --------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------- |
| `scheduledDate` | query      | The date and time the draft payment is executed. Any draft payment in the CSV file is created as a scheduled payment. | No       | date in "YYYY-MM-DD" format |
| `title`         | query      | Title field for the Draft Payment order. Note that this is an API-only field, it won't appear in the user interface.  | No       | string                      |

### CSV format

| Field                      | Required                                   | Description                                                                                                                                    |
| -------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `Name`                     | Yes                                        | Can contain up to 80 characters. If `recipient type` is `INDIVIDUAL`, this field must contain a first and a last name, separated by a space.   |
| `Recipient type`           | Yes                                        | Can be either `INDIVIDUAL` or `COMPANY`.                                                                                                       |
| `Account number`           | For non-IBAN countries                     | Must contain valid account number if provided.                                                                                                 |
| `Sort code`                | For UK local transfers                     | Must contain valid sort code if provided.                                                                                                      |
| `Routing number`           | For US local transfers                     | Must contain valid routing number if provided.                                                                                                 |
| `IBAN`                     | For IBAN countries                         | Must contain valid IBAN if provided.                                                                                                           |
| `BIC`                      | All the countries except for UK/US local   | Must contain valid BIC if provided.                                                                                                            |
| `Recipient bank country`   | Yes                                        | Must contain valid ISO 3166-1 country code.                                                                                                    |
| `Currency`                 | Yes                                        | Must contain valid ISO 4217 currency code.                                                                                                     |
| `Amount`                   | Yes                                        | Must match following pattern `[0-9]*(\.[0-9]*)?`                                                                                               |
| `Payment reference`        | Yes                                        | Can contain up to 100 characters.                                                                                                              |
| `Recipient country`        | For international transfers <br /> (Note: SEPA EUR transfers are treated as local transfers) | Must contain valid ISO 3166-1 country code if provided.                                                                                        |
| `State or province`        | For transfers to US, AU, CA, or MX         | Can contain up to 50 characters.                                                                                                               |
| `Address line 1`           | For international transfers <br /> (Note: SEPA EUR transfers are treated as local transfers) | Can contain up to 50 characters.                                                                                                               |
| `Address line 2`           | No                                         | Can contain up to 50 characters.                                                                                                               |
| `City`                     | For international transfers <br /> (Note: SEPA EUR transfers are treated as local transfers) | Can contain up to 50 characters.                                                                                                               |
| `Postal code`              | For international transfers <br /> (Note: SEPA EUR transfers are treated as local transfers) | Can contain up to 50 characters.                                                                                                               |

## 5. Get a draft payment

Get the details of a draft payment:

- ```shell [Production]
  curl -X GET https://apis.revolut.com/draft-payments/{DraftPaymentId} \
  --header 'Authorization: Bearer <insert access_token>'
  ```

- ```shell [Sandbox]
  curl -X GET https://sandbox-apis.revolut.com/draft-payments/{DraftPaymentId} \
  --header 'Authorization: Bearer <insert access_token>'
  ```

Response:

```json
{
    "Status": "Processed",
    "Transfers": [
        {
            "InstructedAmount": {
                "Amount": "10.00",
                "Currency": "GBP"
            },
            "Reference": "User comment",
            "Status": "Created",
            "Index": 1
        },
        {
            "InstructedAmount": {
                "Amount": "20.00",
                "Currency": "GBP"
            },
            "Reference": "User reference",
            "Status": "Failed",
            "FailedReason": "Something went wrong",
            "FailedReasonCode": 3067,
            "Index": 2
        }
    ]
}
```

Get the details about a specific draft payment with the given draft payment ID.

`Index` indicates the row number the draft payment represents in the CSV file.

## 6. Get list of draft payments

Get a list of draft payments:

- ```shell [Production]
  curl -X GET https://apis.revolut.com/draft-payments?from=<insert_datefrom>&to=<insert_dateto>&limit=<insert_limit> \
  --header 'Authorization: Bearer <insert access_token>'
  ```

- ```shell [Sandbox]
  curl -X GET https://sandbox-apis.revolut.com/draft-payments?from=<insert_datefrom>&to=<insert_dateto>&limit=<insert_limit> \
  --header 'Authorization: Bearer <insert access_token>'
  ```

Response:

```json
{
  "Items": [
              {
                "Id": "d9805904-f722-432c-accd-d0f288c3532e",
                "CreatedAt": "2021-03-28T15:16:20.444101Z",
                "Status": "Awaiting",
                "Title": "test_1"
              },
              {
                "Id": "d9ab7bf0-5781-46ab-b503-d962ae5715ea",
                "CreatedAt": "2021-03-24T19:03:03.367473Z",
                "Status": "Awaiting",
                "Title": "test_2"
              }
          ],
  "Links":
          {
            "Next": "/draft-payments?to=2021-03-24T19:02:21.351937Z&limit=2"
          }
}
```

Get a list of draft payments created by your application.

This endpoint returns draft payments in descending order of creation time and supports pagination: use the `limit` field to specify the number of orders returned in the request. The location of the next page of results will be returned in the `Links.Next` field.

Use the `to` and `from` parameters to specify the date range that you want to pull Draft Payments from by creation date. `from` and `to` dates are inclusive and exclusive of Draft Payments respectively.

### Parameters

| Name          | Located in | Description                                                                                      | Required | Schema                                 |
| ------------- | ---------- | ------------------------------------------------------------------------------------------------ | -------- | -------------------------------------- |
| `from`        | query      | Date and time you retrieve the draft payment orders from.                                        | No       | date in "YYYY-MM-2DDThh:mm:ssZ" format |
| `to`          | query      | The date and time you retrieve the draft payment orders to. The default is now.                  | No       | date in "YYYY-MM-2DDThh:mm:ssZ" format |
| `limit`       | query      | The number of draft payment orders returned via API.                                             | No       | integer                                |

## What's next

- See the [Open Banking API: Create a draft payment](/docs/api/open-banking#create-a-draft-payment) for full details on draft payments.
- To check important considerations when you build your draft payments integration, see [Tutorials: Work with draft payments](/docs/guides/build-banking-apps/tutorials/work-with-draft-payments).
- To request a new endpoint that meets your business requirements, fill out this short [form](https://docs.google.com/forms/d/1jTvhtnCvPvVviGxAqu03vVrnfcrhzkU6KhbAuQvUuQE/edit).