Advanced 35 min read

Build the Callout Service

By the end of this lesson, you'll be able to:

  • Build the payment gateway callout matching the contract from Lesson 1
  • Return a typed result distinguishing success, decline, and error
  • Keep the service itself unaware of Queueable or trigger concerns

Prerequisites: "Design the Payment Flow"

A typed result matching the three outcomes

public class PaymentResult {
    public Boolean success;
    public Boolean declined;
    public String gatewayTransactionId;
    public String message;
}

Three fields directly mirroring Lesson 1's three outcomes — success and declined together let a caller distinguish all three cases (success=true; success=false, declined=true; success=false, declined=false for an error), without needing a separate enum or extra parsing logic.

The callout itself

public class PaymentGatewayService {
    public PaymentResult charge(Decimal amount, String paymentToken) {
        HttpRequest request = new HttpRequest();
        request.setEndpoint('callout:Payment_Gateway/charge');
        request.setMethod('POST');
        request.setBody(JSON.serialize(new Map<String, Object>{
            'amount' => amount,
            'token' => paymentToken
        }));

        HttpResponse response = new Http().send(request);
        Map<String, Object> parsed = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());

        PaymentResult result = new PaymentResult();
        if (response.getStatusCode() == 200) {
            result.success = true;
            result.gatewayTransactionId = (String) parsed.get('transactionId');
        } else if (response.getStatusCode() == 402) { // "Payment Required" — the gateway's decline status
            result.success = false;
            result.declined = true;
            result.message = (String) parsed.get('reason');
        } else {
            result.success = false;
            result.declined = false;
            result.message = 'Gateway error: ' + response.getStatusCode();
        }
        return result;
    }
}

Notice paymentToken, not a raw card number — Lesson 4 covers exactly why. The three-way branch here is a direct implementation of Lesson 1's success/decline/error distinction, using the gateway's actual status codes to tell them apart.

Exercise

As a comment, explain why the service checks response.getStatusCode() == 402 specifically for a decline, rather than treating any non-200 as a decline.

Show hint

Think about what a 500 status would mean instead.

APEX

Build the Callout Service Quiz

1. What do the success and declined fields together let a caller distinguish?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

This lesson builds PaymentGatewayService — a plain, synchronous-looking callout service, deliberately unaware that it will only ever be called from inside an async context.