Skip to content

Commit 4b84170

Browse files
more docs
1 parent af7aaa8 commit 4b84170

File tree

4 files changed

+211
-50
lines changed

4 files changed

+211
-50
lines changed

docs/articles/mandates.md

Lines changed: 175 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,17 +211,166 @@ public async Task RevokeMandate(string mandateId)
211211
}
212212
```
213213

214-
## Mandate States
214+
## Mandate Status
215215

216-
A mandate can be in one of the following states:
216+
Mandates transition through various statuses during their lifecycle. Understanding these statuses helps you track mandate progress and handle different scenarios appropriately.
217217

218-
| State | Description |
219-
|-------|-------------|
220-
| `AuthorizationRequired` | User needs to authorize the mandate |
221-
| `Authorizing` | Authorization is in progress |
222-
| `Authorized` | Mandate is active and can be used for payments |
223-
| `Failed` | Mandate authorization failed |
224-
| `Revoked` | Mandate has been cancelled |
218+
For complete details, see the [TrueLayer Mandate Status documentation](https://docs.truelayer.com/docs/mandate-statuses).
219+
220+
### Status Overview
221+
222+
| Status | Description | Terminal | Notes |
223+
|--------|-------------|----------|-------|
224+
| `authorization_required` | Mandate created but no further action taken | No | User needs to authorize the mandate |
225+
| `authorizing` | User has started but not completed authorization journey | No | Wait for webhook notification |
226+
| `authorized` | User has successfully completed authorization flow | No | Mandate is active and can be used for payments |
227+
| `revoked` | Mandate has been cancelled | Yes | Can be revoked by client or user's bank |
228+
| `failed` | Mandate could not be authorized | Yes | Check `FailureReason` for details |
229+
230+
### Common Failure Reasons
231+
232+
When a mandate reaches `failed` status, check the `FailureReason` property for details:
233+
234+
| Failure Reason | Description |
235+
|----------------|-------------|
236+
| `authorization_failed` | User failed to complete authorization |
237+
| `provider_error` | Error with the provider/bank |
238+
| `provider_rejected` | Provider rejected the mandate |
239+
| `internal_server_error` | TrueLayer processing error |
240+
| `invalid_sort_code` | Invalid bank account sort code |
241+
| `invalid_request` | Request validation failed |
242+
| `expired` | Mandate authorization expired |
243+
| `unknown_error` | Unspecified failure reason |
244+
245+
**Note:** Always handle unexpected failure reasons defensively, as new reasons may be added.
246+
247+
### Checking Mandate Status
248+
249+
```csharp
250+
var response = await _client.Mandates.GetMandate(mandateId, MandateType.Sweeping);
251+
252+
if (response.IsSuccessful)
253+
{
254+
response.Data.Match(
255+
authRequired =>
256+
{
257+
Console.WriteLine($"Status: {authRequired.Status}");
258+
Console.WriteLine("Action: User needs to authorize the mandate");
259+
},
260+
authorizing =>
261+
{
262+
Console.WriteLine($"Status: {authorizing.Status}");
263+
Console.WriteLine("Action: User is authorizing, wait for completion");
264+
},
265+
authorized =>
266+
{
267+
Console.WriteLine($"Status: {authorized.Status}");
268+
Console.WriteLine("Action: Mandate is active and can be used");
269+
},
270+
failed =>
271+
{
272+
Console.WriteLine($"Status: {failed.Status}");
273+
Console.WriteLine($"Failure Reason: {failed.FailureReason}");
274+
Console.WriteLine($"Failed At: {failed.FailedAt}");
275+
Console.WriteLine($"Failure Stage: {failed.FailureStage}");
276+
Console.WriteLine("Terminal: Mandate failed");
277+
},
278+
revoked =>
279+
{
280+
Console.WriteLine($"Status: {revoked.Status}");
281+
Console.WriteLine($"Revoked At: {revoked.RevokedAt}");
282+
Console.WriteLine($"Revoked By: {revoked.RevokedBy}");
283+
Console.WriteLine("Terminal: Mandate has been cancelled");
284+
}
285+
);
286+
}
287+
```
288+
289+
### Handling Terminal Statuses
290+
291+
```csharp
292+
public bool IsTerminalStatus(GetMandateResponse mandate)
293+
{
294+
return mandate.Match(
295+
authRequired => false,
296+
authorizing => false,
297+
authorized => false,
298+
failed => true, // Terminal - mandate failed
299+
revoked => true // Terminal - mandate cancelled
300+
);
301+
}
302+
303+
public async Task WaitForAuthorization(string mandateId, TimeSpan timeout)
304+
{
305+
var startTime = DateTime.UtcNow;
306+
307+
while (DateTime.UtcNow - startTime < timeout)
308+
{
309+
var response = await _client.Mandates.GetMandate(mandateId, MandateType.Sweeping);
310+
311+
if (!response.IsSuccessful)
312+
{
313+
throw new Exception($"Failed to get mandate status: {response.Problem?.Detail}");
314+
}
315+
316+
var isComplete = response.Data.Match(
317+
authRequired => false,
318+
authorizing => false,
319+
authorized => true, // Success
320+
failed => throw new Exception($"Mandate failed: {failed.FailureReason}"),
321+
revoked => throw new Exception("Mandate was revoked")
322+
);
323+
324+
if (isComplete)
325+
{
326+
return; // Mandate authorized successfully
327+
}
328+
329+
await Task.Delay(TimeSpan.FromSeconds(5));
330+
}
331+
332+
throw new TimeoutException("Mandate did not complete authorization within timeout");
333+
}
334+
```
335+
336+
### Handling Specific Failure Reasons
337+
338+
```csharp
339+
public async Task<MandateResult> HandleMandateFailure(string mandateId)
340+
{
341+
var response = await _client.Mandates.GetMandate(mandateId, MandateType.Sweeping);
342+
343+
if (!response.IsSuccessful)
344+
{
345+
return MandateResult.Error("Failed to retrieve mandate status");
346+
}
347+
348+
return response.Data.Match<MandateResult>(
349+
authRequired => MandateResult.RequiresAuth(),
350+
authorizing => MandateResult.Authorizing(),
351+
authorized => MandateResult.Success(),
352+
failed => failed.FailureReason switch
353+
{
354+
"authorization_failed" => MandateResult.Error(
355+
"User failed to complete authorization. Please create a new mandate."
356+
),
357+
"provider_rejected" => MandateResult.Error(
358+
"Provider rejected the mandate. The bank may not support this operation."
359+
),
360+
"expired" => MandateResult.Error(
361+
"Mandate authorization expired. Please create a new mandate."
362+
),
363+
"invalid_sort_code" => MandateResult.Error(
364+
"Invalid bank account details. Please verify and create new mandate."
365+
),
366+
_ => MandateResult.Error($"Mandate failed: {failed.FailureReason}")
367+
},
368+
revoked => MandateResult.Error(
369+
$"Mandate was revoked by {revoked.RevokedBy} on {revoked.RevokedAt}"
370+
)
371+
);
372+
}
373+
```
225374

226375
## Mandate Constraints
227376

@@ -286,11 +435,25 @@ public class User
286435

287436
### 2. Check Mandate Status Before Payment
288437

289-
Always verify mandate is in `Authorized` state:
438+
Always verify mandate is in `authorized` status:
290439

291440
```csharp
292-
var mandate = await GetMandate(mandateId);
293-
if (mandate is not MandateDetail.AuthorizedMandateDetail)
441+
var response = await _client.Mandates.GetMandate(mandateId, MandateType.Sweeping);
442+
443+
if (!response.IsSuccessful)
444+
{
445+
throw new Exception("Failed to retrieve mandate");
446+
}
447+
448+
var isAuthorized = response.Data.Match(
449+
authRequired => false,
450+
authorizing => false,
451+
authorized => true,
452+
failed => false,
453+
revoked => false
454+
);
455+
456+
if (!isAuthorized)
294457
{
295458
throw new InvalidOperationException("Mandate is not authorized");
296459
}

docs/articles/payments.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Create and manage payments using the TrueLayer Payments API. Payments allow you to initiate bank transfers from your users' accounts.
44

5+
> **See also**: The [MVC Example](https://github.com/TrueLayer/truelayer-dotnet/tree/main/examples/MvcExample) demonstrates a complete payment flow in [PaymentsController.cs](https://github.com/TrueLayer/truelayer-dotnet/blob/main/examples/MvcExample/Controllers/PaymentsController.cs).
6+
57
## Basic Payment Creation
68

79
### User-Selected Provider
@@ -95,7 +97,11 @@ var request = new CreatePaymentRequest(
9597

9698
## Beneficiary Types
9799

98-
### External Account (Sort Code & Account Number)
100+
### External Account
101+
102+
Pay to an external bank account using different account identifier types:
103+
104+
#### Sort Code & Account Number
99105

100106
```csharp
101107
var beneficiary = new Beneficiary.ExternalAccount(
@@ -105,7 +111,7 @@ var beneficiary = new Beneficiary.ExternalAccount(
105111
);
106112
```
107113

108-
### IBAN
114+
#### IBAN
109115

110116
```csharp
111117
var beneficiary = new Beneficiary.ExternalAccount(
@@ -160,7 +166,9 @@ var user = new PaymentUserRequest(
160166

161167
### Recommended Approach
162168

163-
The recommended way to use TrueLayer's Hosted Payment Page is to include `HostedPageRequest` when creating the payment. This ensures the HPP URL is generated with the payment and returned in the response:
169+
The recommended way to use TrueLayer's Hosted Payment Page is to include `HostedPageRequest` when creating the payment. This ensures the HPP URL is generated with the payment and returned in the response.
170+
171+
> **See also**: The [MVC Example](https://github.com/TrueLayer/truelayer-dotnet/tree/main/examples/MvcExample) uses `HostedPageRequest` in [PaymentsController.cs](https://github.com/TrueLayer/truelayer-dotnet/blob/main/examples/MvcExample/Controllers/PaymentsController.cs#L51-L69).
164172
165173
```csharp
166174
var hostedPage = new HostedPageRequest(
@@ -250,6 +258,8 @@ Payments transition through various statuses as they progress. Understanding the
250258

251259
For complete details, see the [TrueLayer Payment Status documentation](https://docs.truelayer.com/docs/payment-statuses).
252260

261+
> **See also**: The [MVC Example](https://github.com/TrueLayer/truelayer-dotnet/tree/main/examples/MvcExample) demonstrates handling all payment statuses in [PaymentsController.cs](https://github.com/TrueLayer/truelayer-dotnet/blob/main/examples/MvcExample/Controllers/PaymentsController.cs#L114-L161).
262+
253263
### Status Overview
254264

255265
| Status | Description | Terminal | Notes |

docs/articles/payouts.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Process payouts to send funds from your merchant account to beneficiaries. Payouts are perfect for marketplace disbursements, refunds, and payments to suppliers.
44

5+
> **See also**: The [MVC Example](https://github.com/TrueLayer/truelayer-dotnet/tree/main/examples/MvcExample) demonstrates a complete payout flow in [PayoutController.cs](https://github.com/TrueLayer/truelayer-dotnet/blob/main/examples/MvcExample/Controllers/PayoutController.cs).
6+
57
## Basic Payout Creation
68

79
### Payout to UK Account
@@ -104,6 +106,8 @@ Payouts transition through various statuses as they are processed. Understanding
104106

105107
For complete details, see the [TrueLayer Payout and Refund Status documentation](https://docs.truelayer.com/docs/payout-and-refund-statuses).
106108

109+
> **See also**: The [MVC Example](https://github.com/TrueLayer/truelayer-dotnet/tree/main/examples/MvcExample) demonstrates handling all payout statuses in [PayoutController.cs](https://github.com/TrueLayer/truelayer-dotnet/blob/main/examples/MvcExample/Controllers/PayoutController.cs#L90-L127).
110+
107111
### Status Overview
108112

109113
| Status | Description | Terminal | Notes |

0 commit comments

Comments
 (0)