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.
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.
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)- Reference
- Official developer docs
Key endpoints
createTransactionRequest (authOnly / authCapture / priorAuthCapture / refund)createCustomerProfileRequest (CIM)createCustomerPaymentProfileRequest (CIM)SF CommercePayments: AuthorizationRequest, CaptureRequest, ReferencedRefundRequest, TokenizeRequestWebhook and platform events
net.authorize.payment.authcapture.creatednet.authorize.payment.authorization.creatednet.authorize.payment.refund.creatednet.authorize.payment.void.createdBuild 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...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.
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
What you will need
What we confirm on both sides before writing a line of code.
From trigger to record, end to end
The production runtime flow, with what happens in each system.
- 01
Customer pays
In Authorize.NetA 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. - 02
Event is emitted
In transitAuthorize.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. - 03
Verified and queued
In SalesforceThe 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. - 04
Record is written
In SalesforceThe 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. - 05
Reconciled and reported
In SalesforceThe payment is matched to the right record; refunds and disputes flow back automatically.
$Amounts reconciled against invoices, with exceptions raised on a dashboard.
How the data actually flows
Left to right: sources, the integration layer, Salesforce, and the outcomes it drives.
// sources feed the integration layer, Salesforce persists, outcomes ship
The objects behind the integration
The Salesforce objects we read and write, what each one is for, and the fields that carry the load.
| Object | Purpose | Key fields |
|---|---|---|
Payment | The 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 |
Account | Matched 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
Build the Authorize.Net integration
Every step we follow to ship a production-grade build, with the code that matters.
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
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
@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
}
}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.
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
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
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.
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
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());
}
}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
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
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
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
Example field mapping
How Authorize.Net data lands on your Salesforce records. We tailor the full mapping to your org.
| Authorize.Net | Salesforce | Notes |
|---|---|---|
| Authorize.Net charge id | Payment.External_Id__c | Unique external id, upsert key |
| Authorize.Net amount | Payment.Amount | |
| Authorize.Net currency | Payment.CurrencyIsoCode | |
| Authorize.Net customer | Account | Matched or created |
| Authorize.Net status | Payment.Status | Picklist value mapping |
| Created / updated at | LastModifiedDate | Enables delta sync and audit |
| Owner or rep | Payment.OwnerId | Assignment rules or a default owner |
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 platform limits
Secure by design
How we keep the integration safe, least-privilege, and compliant.
Monitoring, retries, and reliability
What keeps the integration trustworthy in production, and how you know the moment something needs attention.
How we test, deploy, and hand it over
The quality gates every build clears before it touches your production org.
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
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.
