Technical guide

Authorize.Net technical guide

Everything an engineer needs to connect Authorize.Net to Salesforce: architecture, the exact build steps with real code, field mapping, the data model, security, monitoring, and the pitfalls we design out.

Platform: Authorize.NetType: Payment gatewayDirection: CheckoutObjects: Account, Payment

A custom payment gateway for Salesforce B2B Commerce checkout. We have shipped it across 7 client projects and 34 build tasks.

The value is what happens after the charge: matching payments to records, handling refunds, and keeping finance reconciled without manual work.

We build a hardened webhook pipeline: a public Apex REST endpoint on a Salesforce Site, signature verification on every event, and flows that turn raw Authorize.Net events into clean, reconciled records.

Every Authorize.Net build is delivered by a senior Salesforce architect on a fixed price, tested end to end in a sandbox, deployed to your org, and backed by 30 days of hypercare. You own the result: documented, source-controlled, and free of black-box middleware lock-in.

the connection at a glancesync active
01Authorize.Net
02Salesforce Site
03Apex REST
04Events object
05Flows
06Records
Integration facts

How Authorize.Net connects to Salesforce

The real connection surface: how it authenticates, what it is built on, the endpoints and events in play, and where the reference docs live.

Connects via
Custom Apex adapter implementing the CommercePayments.PaymentGatewayAdapter interface (processRequest)Outbound callout to Authorize.Net via a Named CredentialAuthorize.Net CIM customer/payment profiles for stored cards outside the paved checkout
Package
Custom build (no managed package)
Authentication
Authorize.Net merchantAuthentication = API Login ID + Transaction Key, stored in a Named Credential or protected custom setting; PAN never stored in Salesforce
API type
REST/XML
https://api.authorize.net/xml/v1/request.api (sandbox: https://apitest.authorize.net/xml/v1/request.api)

Key endpoints

createTransactionRequest (authOnly / authCapture / priorAuthCapture / refund)createCustomerProfileRequest (CIM)createCustomerPaymentProfileRequest (CIM)SF CommercePayments: AuthorizationRequest, CaptureRequest, ReferencedRefundRequest, TokenizeRequest

Webhook and platform events

net.authorize.payment.authcapture.creatednet.authorize.payment.authorization.creatednet.authorize.payment.refund.creatednet.authorize.payment.void.created
Free download

Build this with AI agents

Copy the full playbook as a prompt for any coding agent, or install it as a Claude Code skill. Either way your agent builds with our exact approach: the architecture, the Apex code, the field mapping, the rate limits, and the pitfalls to design out. Free, no signup.

Loading the Authorize.Net playbook...
Paste into Claude Code, Cursor, or any coding agent
From our builds

What we build for a Authorize.Net integration

Authorize.Net built as the payment gateway for Salesforce B2B Commerce checkout: a custom Payment Gateway Adapter and CommercePayments classes implementing Tokenization, Authorization and Capture, with reusable customer profiles and full test coverage.

6client projects
34delivery tasks shipped

Commerce payment adapter

A custom Payment Gateway Adapter on the Salesforce CommercePayments framework implementing the three-stage Tokenization, Authorization and Capture flow.

Reusable customer profiles

Invocable Apex to create and retrieve Authorize.Net CIM customer profiles, storing the auth.net customer id on Account for hosted payment and saved cards.

Webhook status updates

A secured Apex REST resource on a Salesforce Site that updates invoice status from Authorize.Net webhook approvals, logging every request and response to an Error Log object.

Test coverage for deployment

Wrote AuthorizeAdapterTest and AuthorizationTransactionServiceTest to carry the build safely through deployment.

Real components we ship

Custom PaymentGatewayAdapterCommercePayments Tokenize / Authorize / CaptureAuthorize.Net CIM customer profilesauth.net customer id on AccountSaved card (last-4 and card type)Apex REST invoice-status webhookError_Log__c objectAuthorizeAdapterTest / AuthorizationTransactionServiceTest
Step 0

What you will need

What we confirm on both sides before writing a line of code.

A Salesforce edition with API access (Enterprise, Unlimited, or Developer)
A dedicated sandbox to build and test in
Authorize.Net test-mode credentials to validate before going live
A Salesforce Site to host the public webhook endpoint
A Authorize.Net account on a plan with API access
System Administrator access on both systems
A dedicated integration user with a minimum-access permission set
Agreement on the objects, fields, and sync direction for the Authorize.Net data
How it works

From trigger to record, end to end

The production runtime flow, with what happens in each system.

runtime sequence5 steps
  1. 01

    Customer pays

    In Authorize.Net

    A customer or donor pays through Authorize.Net using checkout, a payment link, or a saved card.

    $Handled entirely vendor-side, so raw card data never touches Salesforce and PCI scope stays low.
  2. 02

    Event is emitted

    In transit

    Authorize.Net emits an event such as checkout.session.completed or charge.succeeded.

    $POSTed over Custom Apex, CommercePayments to a public Apex REST endpoint exposed on a Salesforce Site.
  3. 03

    Verified and queued

    In Salesforce

    The endpoint verifies the signature, returns HTTP 200 immediately, and hands the work off.

    $HMAC signature checked; heavy processing runs in a Queueable so the webhook never hits its timeout.
  4. 04

    Record is written

    In Salesforce

    The event is upserted to an Events object, then mapped onto the Payment and Account.

    $Idempotent upsert on the event id; a record-triggered flow maps fields and reconciles.
  5. 05

    Reconciled and reported

    In Salesforce

    The payment is matched to the right record; refunds and disputes flow back automatically.

    $Amounts reconciled against invoices, with exceptions raised on a dashboard.
Architecture

How the data actually flows

Left to right: sources, the integration layer, Salesforce, and the outcomes it drives.

system architecture
Sources
Authorize.Net checkout
Authorize.Net events
Custom Apex, CommercePayments
Integration layer
Webhook / API handler
Payment flows
Reconciliation jobs
Salesforce
Payment
Related records
Reports
Outcomes
Payments reconciled
Records created
No manual entry

// sources feed the integration layer, Salesforce persists, outcomes ship

Data model

The objects behind the integration

The Salesforce objects we read and write, what each one is for, and the fields that carry the load.

ObjectPurposeKey fields
PaymentThe primary Salesforce record Authorize.Net data maps onto.External_Id__c, Name, Status
Inbound_Event__c (custom)Stores each raw event idempotently for audit and replay.Event_Id__c, Payload__c, Processed__c
AccountMatched or created for the customer or company behind the record.Name, External_Id__c
Error_Log__c (custom)Captures every request, response, and failure so anything can be replayed.Payload__c, Status__c, Related_Id__c

Salesforce objects typically in play for Authorize.Net

PaymentGatewayPaymentGatewayLogPaymentAuthorizationPaymentCardPaymentMethod
Step by step

Build the Authorize.Net integration

Every step we follow to ship a production-grade build, with the code that matters.

1

Plan the integration and prerequisites

We agree the events that matter and design a secure public endpoint before touching code.

  • A Salesforce edition with API access, a dedicated sandbox, and a Salesforce Site for the public URL
  • A Authorize.Net account in test mode first, with admin access on both systems
  • The exact events, target objects, and reconciliation rules agreed up front
  • A hardened Site guest user with the absolute minimum permissions
2

Build the Apex REST endpoint

We give Authorize.Net a typed, testable place to POST events.

  • An @RestResource class with an @HttpPost handler mapped to a stable URL
  • The raw request body is read once and kept for signature verification and audit
InboundWebhookResource.clsapex
@RestResource(urlMapping='/webhook/*')
global with sharing class InboundWebhookResource {
  @HttpPost
  global static void handle() {
    RestRequest req = RestContext.request;
    String raw = req.requestBody.toString();

    if (!WebhookSignature.isValid(raw, req.headers.get('X-Signature'))) {
      RestContext.response.statusCode = 401;      // reject unverified events
      return;
    }
    Inbound_Event__c e = new Inbound_Event__c(
      Event_Id__c = EventParser.idOf(raw), Payload__c = raw);
    upsert e Event_Id__c;                         // idempotent capture
    System.enqueueJob(new EventProcessor(e.Id));  // process asynchronously
    RestContext.response.statusCode = 200;         // respond fast
  }
}
3

Expose it securely on a Salesforce Site

We make the endpoint reachable without opening the whole org.

  • Create a Salesforce Site and enable only the one Apex class for the guest user
  • The public URL follows /services/apexrest/...; every other guest permission stays off

Watch out: lock down the guest user

A Salesforce Site runs as a guest user. Grant it access to only the one Apex class, or you expose far more of the org than a webhook ever should.

4

Register the webhook in Authorize.Net

We subscribe to exactly the events we need, nothing more.

  • In the Authorize.Net dashboard, add the endpoint URL and select the relevant events (checkout, charge, invoice, refund, and so on)
  • Copy the webhook signing secret into a protected custom setting or custom metadata
5

Verify signatures and prevent replay

We make sure only genuine, once-only events ever change data.

  • Compute an HMAC-SHA256 of the raw body with the signing secret and constant-time compare it
  • Reject on mismatch, and check the event timestamp to block replay attacks
WebhookSignature.clsapex
public class WebhookSignature {
  public static Boolean isValid(String rawBody, String header) {
    Blob secret = Blob.valueOf(WebhookConfig.signingSecret());
    Blob mac = Crypto.generateMac('HmacSHA256', Blob.valueOf(rawBody), secret);
    String expected = EncodingUtil.convertToHex(mac);
    // constant-time compare guards against timing attacks
    return ConstantTime.equals(expected, header);
  }
}

Watch out: verify every event

A public endpoint is a target. Validate the signing secret and make the handler idempotent, or a retried or spoofed event can double-post to your records.

6

Respond fast, process asynchronously

We never let processing block the webhook response.

  • Return HTTP 200 within the vendor timeout, which is usually only a few seconds
  • Hand the heavy work to a Queueable so slow processing never triggers a retry storm
EventProcessor.clsapex
public class EventProcessor implements Queueable {
  private Id eventId;
  public EventProcessor(Id eventId) { this.eventId = eventId; }

  public void execute(QueueableContext ctx) {
    Inbound_Event__c e = [SELECT Payload__c FROM Inbound_Event__c WHERE Id = :eventId];
    Map<String,Object> body = (Map<String,Object>) JSON.deserializeUntyped(e.Payload__c);
    // heavy work runs here, off the webhook thread: map onto Accounts, Cases, Payments
    EventRouter.route(body);
    update new Inbound_Event__c(Id = eventId, Processed__c = true, Processed_At__c = System.now());
  }
}
7

Capture raw events idempotently

We keep a durable, replayable record of everything received.

  • Upsert an Inbound_Event__c on the event id so duplicate deliveries are ignored
  • Store the raw JSON for audit and for replay if a downstream mapping ever changes
8

Map events onto your Payment

We turn raw Authorize.Net events into clean Salesforce data.

  • Flows or triggers translate events onto Accounts, Payment, Payments, and Cases
  • Store the Authorize.Net ids on the records and handle out-of-order events gracefully
9

Handle money and edge cases

We cover the cases that otherwise become disputes.

  • Reconcile payments, and handle refunds, chargebacks, and partial captures
  • Backfill missing data and alert on any mismatch before it reaches finance
10

Test, deploy, and monitor

We prove it end to end and keep watch in production.

  • Apex tests build a RestContext request and assert the resulting records; replay real test-mode events
  • Deploy via change sets, restrict the events object to admins, and monitor with error logging plus 30 days of support
Field mapping

Example field mapping

How Authorize.Net data lands on your Salesforce records. We tailor the full mapping to your org.

Authorize.NetSalesforceNotes
Authorize.Net charge idPayment.External_Id__cUnique external id, upsert key
Authorize.Net amountPayment.Amount
Authorize.Net currencyPayment.CurrencyIsoCode
Authorize.Net customerAccountMatched or created
Authorize.Net statusPayment.StatusPicklist value mapping
Created / updated atLastModifiedDateEnables delta sync and audit
Owner or repPayment.OwnerIdAssignment rules or a default owner
API & limits

Rate limits and governor limits

The platform constraints we design around, so the integration stays fast and never falls over at scale.

Specific to Authorize.Net

Salesforce Apex callout limits (100 callouts/transaction, 120s, max 10 concurrent long-running requests)
B2B Commerce paved flow supports only CardPaymentMethod + single-use tokenization (no saved methods in checkout)
Authorize.Net per-account transaction and velocity limits

Salesforce platform limits

A webhook handler must return within Authorize.Net's timeout, usually a few seconds. We acknowledge with HTTP 200 immediately and process the event asynchronously.
Salesforce Sites have their own request limits. Heavy processing is offloaded to a Queueable so the public endpoint stays fast.
Authorize.Net retries failed deliveries automatically. Idempotency on the event id means a retried event is never processed twice.
Security

Secure by design

How we keep the integration safe, least-privilege, and compliant.

Secrets stored in Named Credentials and permission sets, never in code or metadata
A least-privilege integration user, with field-level security and sharing scoped tight
All traffic over TLS, with signature verification on inbound events
Card data never touches Salesforce, keeping your PCI scope minimal
Shield Platform Encryption available for sensitive fields
A full audit trail: every request and response logged for traceability
Every automation runs as a dedicated integration user, so actions are attributable and revocable
Sandbox-first delivery and change-set deployment keep production changes reviewed and controlled
Monitoring

Monitoring, retries, and reliability

What keeps the integration trustworthy in production, and how you know the moment something needs attention.

Every request and response is logged to a custom Error Log object, tagged with the related record id.
Failed calls retry with exponential backoff; anything still failing lands in a dead-letter queue for review.
Idempotency keys guarantee a retried or duplicate event never double-posts a record.
A dashboard surfaces failures, latency, and volume so problems are caught before users notice.
Optional email or Slack alerts fire on repeated failures or a stalled sync.
Testing & deployment

How we test, deploy, and hand it over

The quality gates every build clears before it touches your production org.

Apex unit tests with HttpCalloutMock cover the success path, failure handling, and a 200-record bulk case, at 75 percent or higher coverage.
The full flow is validated in a sandbox against real sample data and the edge cases that matter.
A parallel run reconciles the integration against your live system before cutover.
Everything deploys through change sets or an SFDX and CI pipeline, under version control.
Permission sets, sharing, and Named Credentials are configured in production, then we run 30 days of monitored hypercare.
Pitfalls

Common pitfalls we design out

The mistakes that quietly break integrations, and how we avoid each one.

Missed or duplicated events

Verify signatures, upsert on the event id, and return 200 within the timeout.

Webhook times out on heavy processing

Acknowledge fast and process the event in a Queueable.

Guest user exposes too much

Grant the Site guest user access to only the single Apex class.

No visibility when it breaks

We log every call and surface failures on a dashboard with alerts, so an issue never goes unnoticed.

Reporting drifts from reality

External-id keys and a delta timestamp keep Salesforce and the source reconciled, so reports stay trustworthy.

Gotchas specific to Authorize.Net

The paved tokenize-to-authorize flow supports only single-use tokens; saved cards / CIM profiles must be handled outside it
Stay PCI-compliant: log to PaymentGatewayLog, never persist the PAN
Gateway response mapping must translate Authorize.Net result, AVS and CVV codes into CommercePayments GatewayResponse subclasses
FAQ

Authorize.Net integration: technical FAQs

How do you authenticate Authorize.Net with Salesforce?

We connect Authorize.Net using secure named credentials and store every secret in Salesforce Named Credentials with a permission set, so nothing is hard-coded or shipped in metadata.

Does the Authorize.Net integration handle bulk volume?

Yes. All Apex is bulkified, volume moves to Queueable or Batch Apex, and we respect the Salesforce governor limits (SOQL, DML, and callout caps per transaction).

How do you prevent duplicate records?

We upsert on a unique external-id field, so a retried or duplicate payload is idempotent and never creates a second Payment.

How is the integration tested and deployed?

Apex tests with HttpCalloutMock cover the success, failure, and a 200-record bulk case (75 percent plus coverage). We deploy via change sets or an SFDX and CI pipeline.

What happens if Authorize.Net or Salesforce is briefly down?

Failed calls retry with backoff and land in an Error Log object with alerting, so nothing is lost and any event can be replayed.

How do you secure the webhook endpoint?

The Apex REST endpoint runs on a Salesforce Site with a locked-down guest user, verifies the HMAC signature on every event, and checks the timestamp to block replays.

Want us to build your Authorize.Net integration?

Skip the build. In a free 30-minute call we will map your Authorize.Net flow and hand you a clear, fixed-price plan.

Ask me anything