# EFT Debit orders (/docs/direct-debit/eft-debit-orders)

EFT debit orders (standard debit orders) enable merchants to collect funds from customer bank accounts with written, electronic, or voice-recorded authorisation.

## Overview [#overview]

EFT debit orders are cost-efficient payment instruments for collecting recurring revenue. The process involves:

1. **Create a Mandate**: Obtain and store customer authorisation
2. **Create Collections**: Submit collection instructions against the mandate
3. **Monitor Status**: Track collection results and handle failures

## Service Types [#service-types]

| Service Type | Description | Settlement |
|---|---|---|
| `SAMEDAY` | Processed and settled same day | Same day |
| `ONEDAY` | Processed within one business day | Next business day |
| `TWODAY` | Processed within two business days | Two business days |

## Mandates [#mandates]

A mandate represents the customer's authorisation to debit their account.

### Create EFT Mandate [#create-eft-mandate]

### Endpoint [#endpoint]

```text
POST https://api.revio.co.za/v2/mandate/eft/
```

### Request [#request]

```bash
curl -X POST https://dev.api.revio.co.za/v2/mandate/eft/ \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "defaultServiceType": "ONEDAY",
    "profileCode": "TEST1",
    "abbreviatedName": "TESTMERCH1",
    "contractReference": "CONTRACT001",
    "debtor": {
      "accountNumber": "010553922",
      "accountType": "CURRENT",
      "bank": "ABSA",
      "branchCode": "632005",
      "firstName": "John",
      "lastName": "Smith",
      "identification": {
        "emailAddress": "john@example.com",
        "idNumber": "0001010000006",
        "phoneNumber": "+27-123456789",
        "passportNumber": ""
      }
    },
    "creditor": {
      "accountNumber": "12345678",
      "accountType": "CURRENT",
      "branchCode": "051001",
      "name": "TEST MERCHANT 1",
      "bank": "STANDARDBANK",
      "phoneNumber": "+27-615333440",
      "emailAddress": "merchant@test.com"
    },
    "releaseDate": "2024-12-31T00:00:00.000Z",
    "frequency": "MONTHLY",
    "collectionDay": 15,
    "amountCents": 10000,
    "currency": "ZAR",
    "entryClass": "21",
    "verifyAccount": false
  }'
```

### Request Fields [#request-fields]

| Field | Type | Required | Description |
|---|---|---|---|
| `defaultServiceType` | string | Yes | Default service type: `SAMEDAY`, `ONEDAY`, `TWODAY` |
| `profileCode` | string | Yes | Your merchant profile code |
| `abbreviatedName` | string | Yes | Your PASA-registered abbreviated name |
| `contractReference` | string | Yes | Unique contract reference (max 14 characters) |
| `externalReference` | string | No | Your external reference ID (must be unique) |
| `debtor` | object | Yes | Customer (payer) details |
| `creditor` | object | Yes | Merchant (payee) details |
| `ultimateCreditor` | object | No | Split payment recipient (if required) |
| `releaseDate` | string | No | Date when mandate becomes active |
| `frequency` | string | Yes | Collection frequency |
| `collectionDay` | integer | Yes | Day of month for collections (1-31) |
| `amountCents` | integer | Yes | Collection amount in cents |
| `currency` | string | Yes | Currency code (`ZAR`) |
| `entryClass` | string | Yes | Always `21` |
| `verifyAccount` | boolean | No | Perform bank account verification |

### Debtor Object [#debtor-object]

| Field | Type | Required | Description |
|---|---|---|---|
| `accountNumber` | string | Yes | Customer bank account number |
| `accountType` | string | Yes | Account type: `CURRENT`, `SAVINGS`, `TRANSMISSION` |
| `bank` | string | Yes | Bank name (uppercase, one word) |
| `branchCode` | string | Yes | Bank branch code |
| `firstName` | string | Yes | Customer first name |
| `lastName` | string | Yes | Customer last name |
| `identification.emailAddress` | string | Yes | Customer email |
| `identification.idNumber` | string | Yes | SA ID number |
| `identification.phoneNumber` | string | Yes | Phone number (format: `+27-XXXXXXXXX`) |
| `identification.passportNumber` | string | No | Passport number (if no ID) |

### Creditor Object [#creditor-object]

| Field | Type | Required | Description |
|---|---|---|---|
| `accountNumber` | string | Yes | Your settlement account number |
| `accountType` | string | Yes | Account type |
| `branchCode` | string | Yes | Your bank branch code |
| `name` | string | Yes | Your registered merchant name |
| `bank` | string | Yes | Your bank name |
| `phoneNumber` | string | Yes | Your contact number |
| `emailAddress` | string | Yes | Your email address |

### Frequency Values [#frequency-values]

| Value | Description |
|---|---|
| `WEEKLY` | Every week |
| `MONTHLY` | Every month |
| `QUARTERLY` | Every 3 months |
| `BIANNUALLY` | Every 6 months |
| `ANNUALLY` | Every year |

### Bank Names [#bank-names]

Use uppercase, single-word format:

- `ABSA`
- `STANDARDBANK`
- `FNB`
- `NEDBANK`
- `CAPITEC`
- `INVESTEC`
- `BIDVEST`

### Response [#response]

```json
{
  "id": "8f4a6b0f-fa9b-4f45-8e19-b75c1a70432a",
  "status": "ACTIVE",
  "defaultServiceType": "ONEDAY",
  "profileCode": "TEST1",
  "abbreviatedName": "TESTMERCH1",
  "contractReference": "CONTRACT001",
  "debtor": { ... },
  "creditor": { ... },
  "frequency": "MONTHLY",
  "collectionDay": 15,
  "amountCents": 10000,
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

### Bank Account Verification [#bank-account-verification]

Set `verifyAccount: true` to verify the debtor's bank account before creating the mandate:

```json
{
  "verifyAccount": true
}
```

The verification checks:

- Account exists
- Account is open
- Account type matches
- Account accepts debits
- ID number matches the account holder

If verification fails, the mandate will not be created. See Bank Account Verification for details.

### Ultimate Creditor (Split Payments) [#ultimate-creditor-split-payments]

For split payment scenarios, include the `ultimateCreditor` object:

```json
{
  "ultimateCreditor": {
    "accountNumber": "010553983",
    "accountType": "CURRENT",
    "branchCode": "051001",
    "name": "PARTNER COMPANY",
    "bank": "STANDARDBANK",
    "phoneNumber": "+27-615333440",
    "emailAddress": "partner@test.com",
    "idNumber": "0001010000089"
  }
}
```

## Collections [#collections]

Collections are individual debit instructions processed against a mandate.

### Create EFT Collection [#create-eft-collection]

### Endpoint [#endpoint-1]

```text
POST https://api.revio.co.za/v2/collection/eft/from_mandate/
```

### Request [#request-1]

```bash
curl -X POST https://dev.api.revio.co.za/v2/collection/eft/from_mandate/ \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mandateId": "8f4a6b0f-fa9b-4f45-8e19-b75c1a70432a",
    "collectionDate": "2024-02-15T00:00:00.000Z",
    "amountCents": 10000,
    "serviceType": "ONEDAY"
  }'
```

### Request Fields [#request-fields-1]

| Field | Type | Required | Description |
|---|---|---|---|
| `mandateId` | string | Yes | ID of the mandate to collect against |
| `collectionDate` | string | Yes | Date to process collection (ISO 8601) |
| `amountCents` | integer | Yes | Collection amount in cents |
| `externalReference` | string | No | Your external reference ID |
| `serviceType` | string | No | Override default service type |

### Response [#response-1]

```json
{
  "id": "63d94be3-1faf-428b-89f3-bc5271be8015",
  "mandateId": "8f4a6b0f-fa9b-4f45-8e19-b75c1a70432a",
  "status": "PENDING",
  "collectionDate": "2024-02-15T00:00:00.000Z",
  "amountCents": 10000,
  "serviceType": "ONEDAY"
}
```

### Get Collection Status [#get-collection-status]

### Endpoint [#endpoint-2]

```text
GET https://api.revio.co.za/v2/collection/eft/{collectionId}/status/
```

### Request [#request-2]

```bash
curl -X GET https://dev.api.revio.co.za/v2/collection/eft/63d94be3-1faf-428b-89f3-bc5271be8015/status/ \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

### Response [#response-2]

```json
{
  "id": "63d94be3-1faf-428b-89f3-bc5271be8015",
  "status": "COMPLETED",
  "statementId": "stmt_12345"
}
```

### Collection Statuses [#collection-statuses]

| Status | Description |
|---|---|
| `PENDING` | Collection submitted, awaiting processing |
| `PROCESSING` | Collection being processed by bank |
| `COMPLETED` | Collection successful |
| `UNPAID` | Collection failed (insufficient funds, etc.) |
| `DISPUTED` | Customer disputed the collection |
| `CANCELLED` | Collection cancelled before processing |

## Bank Account Verification [#bank-account-verification-1]

Verify customer bank details before creating mandates.

### Verification Checks [#verification-checks]

| Check | Field | Description |
|---|---|---|
| `AccountExists` | Account number | Account exists at bank |
| `AccountIsOpen` | Account status | Account is active/open |
| `AccountTypeMatches` | Account type | Provided type matches actual |
| `AccountAcceptsDebits` | Account capabilities | Account can receive debits |
| `IdNumberMatches` | ID number | ID matches account holder |

### Failure Response [#failure-response]

```json
{
  "value": {
    "Message": "Debtor account verification failure: details={\"AccountExists\":true,\"AccountIsOpen\":false,\"AccountTypeMatches\":null,\"IdNumberMatches\":null,\"AccountAcceptsDebits\":null}"
  },
  "statusCode": 400
}
```

## Cut-off Times [#cut-off-times]

Submit collections before these cut-off times:

| Service Type | Weekday Cut-off | Weekend Cut-off |
|---|---|---|
| Same-day | 08:00 - 16:20 | 08:00 - 09:45 |
| One-day (dated) | 08:00 - 16:00 | 08:00 - 10:15 |
| Two-day (dated) | 08:00 - 14:30 (2 days before) | 08:00 - 09:00 |

## Reconciliation [#reconciliation]

Revio automatically reconciles collection results to bank statements. Successfully reconciled collections include a `statementId` field:

```json
{
  "id": "63d94be3-1faf-428b-89f3-bc5271be8015",
  "status": "COMPLETED",
  "statementId": "stmt_12345"
}
```

Contact your Revio account manager to enable automatic reconciliation.

## Error Handling [#error-handling]

### Common Errors [#common-errors]

| Error | Cause | Resolution |
|---|---|---|
| `400 Bad Request` | Invalid request data | Check required fields and formats |
| `404 Not Found` | Mandate/collection not found | Verify the ID |
| `409 Conflict` | Duplicate external reference | Use a unique reference |

### Unpaid Collections [#unpaid-collections]

When a collection returns unpaid:

- Do not resubmit until the next mandated date
- After 2 consecutive "Not provided for" failures, obtain a new mandate
- "Account Closed" or "Payment Stopped" requires customer contact

## Best Practices [#best-practices]

1. **Store mandate IDs**: Keep track of mandate IDs for future collections
2. **Use external references**: Add your own references for easier reconciliation
3. **Handle failures gracefully**: Implement retry logic respecting PASA rules
4. **Verify accounts**: Use `verifyAccount: true` to reduce failed collections
5. **Submit early**: Submit collections well before cut-off times
