Last updated

Building Custom Adapters

Norce Checkout supports custom adapters that integrate external payment providers, shipping services, or other third-party systems. This guide covers the technical requirements and patterns for building your own adapter.

Architecture Overview

Adapters follow a stateless orchestration pattern where they act as intermediaries between your external provider and the Norce Checkout Order API. The Order API serves as the single source of truth for all order data.

The typical flow for any adapter operation is:

  1. Receive a request from your checkout frontend
  2. Fetch the current order state from the Order API
  3. Retrieve your adapter configuration from the Configuration API
  4. Apply your business logic and call your external provider
  5. Persist any changes back to the Order API
  6. Return the response to your frontend

This pattern ensures data consistency and allows adapters to scale horizontally without managing local state.

API Integration

Order API

The Order API is your primary integration point. All order data, including cart contents, customer information, payments, and shipping details, is managed through this API.

Common operations include:

GET /api/v0/checkout/orders/{orderId}
Host: {slug}.api-se.{environment}.norce.tech/checkout/order
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}
POST /api/v0/checkout/orders/{orderId}/payments
Host: {slug}.api-se.{environment}.norce.tech/checkout/order
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}
Content-Type: application/json

{
  "adapterId": "your_adapter_id",
  "reference": "external-payment-reference",
  "name": "Your Payment Method",
  "amount": 100.00,
  "state": "intent"
}

For the complete API specification, see the Order API Reference.

Configuration API

The Configuration API stores adapter-specific settings for each merchant and channel combination. Your adapter retrieves its configuration at runtime to access credentials, feature flags, and other settings.

GET /api/v1/configuration/merchants/{merchant}/channels/{channel}/configurations/{adapter_id}
Host: {slug}.api-se.{environment}.norce.tech/checkout/configuration
Authorization: Bearer {token}

Configuration Schema

Your adapter must provide a JSON schema that defines its configuration structure. This schema enables validation and provides documentation for merchants configuring your adapter.

The schema must extend the base configuration structure:

{
  "$schema": "https://your-adapter.example.com/openapi/v1/schemas/your_adapter.json",
  "id": "your_adapter_id",
  "active": true,
  "adapter": {
    "internalUrl": "https://your-adapter.example.com",
    "publicUrl": "https://your-adapter.example.com"
  }
}

The adapter.internalUrl and adapter.publicUrl fields can use the same URL for externally hosted adapters. Add your adapter-specific settings as additional properties in the schema.

Example Schema

{
  "$schema": "http://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["$schema", "id", "active", "adapter", "provider"],
  "properties": {
    "$schema": {
      "type": "string"
    },
    "id": {
      "type": "string",
      "description": "Unique configuration identifier"
    },
    "active": {
      "type": "boolean"
    },
    "adapter": {
      "type": "object",
      "required": ["internalUrl", "publicUrl"],
      "properties": {
        "internalUrl": { "type": "string", "format": "uri" },
        "publicUrl": { "type": "string", "format": "uri" }
      }
    },
    "provider": {
      "type": "object",
      "required": ["apiKey", "environment"],
      "properties": {
        "apiKey": { "type": "string" },
        "merchantId": { "type": "string" },
        "environment": {
          "type": "string",
          "enum": ["test", "production"]
        }
      }
    }
  }
}

Host your schema at a publicly accessible URL. The Configuration API validates configurations against this schema when merchants save their settings.

Hooks and Notifications

Hooks and notifications enable your adapter to react to order changes and maintain synchronization with external systems.

Hooks

Hooks are synchronous callbacks that allow your adapter to validate or modify order changes before they are committed. Register hooks when creating a payment or shipping entry.

POST /api/v0/checkout/orders/{orderId}/hooks
Host: {slug}.api-se.{environment}.norce.tech/checkout/order
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}
Content-Type: application/json

{
  "adapterId": "your_adapter_id",
  "subscribeTo": "/cart",
  "target": "/payments",
  "invoke": "https://your-adapter.example.com/api/v1/callback/orders/{orderId}/payments/{paymentId}/cart-changed"
}

Available hook scopes include /cart, /shippings, /customer, /payments, and /state. Your hook endpoint receives the proposed changes and returns JSON Patch operations to apply additional modifications, or an error to reject the change.

Notifications

Notifications are asynchronous events sent after changes are committed. Use notifications for operations that don't need to block the checkout flow.

POST /api/v0/checkout/orders/{orderId}/notifications
Host: {slug}.api-se.{environment}.norce.tech/checkout/order
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}
Content-Type: application/json

{
  "adapterId": "your_adapter_id",
  "reference": "order-completed-notification",
  "description": "Notify adapter when order completes",
  "scope": "/state/currentStatus",
  "schema": {
    "enum": ["accepted", "completed"]
  },
  "invoke": "https://your-adapter.example.com/api/v1/callback/orders/{orderId}/order-completed"
}

For detailed information on implementing hooks and notifications, see the Hooks and Custom Notifications guides.

Order State Management

Understanding the order state machine is essential for payment adapters. Orders progress through these states:

StateDescription
checkoutOrder is being built, modifications allowed
processingPayment validation in progress, order locked
acceptedPayment authorized, awaiting capture
completedOrder finalized, payment captured

Your adapter triggers state transitions by calling the Order API:

POST /api/v0/checkout/orders/{orderId}/state
Host: {slug}.api-se.{environment}.norce.tech/checkout/order
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}
Content-Type: application/json

{
  "state": "processing"
}

When transitioning to processing, all registered hooks execute. If any hook rejects the transition, the state change fails and the order remains in checkout.

Payment Adapter Implementation

Payment adapters typically implement these operations:

Create Payment Session

When your frontend initiates checkout with your payment method, create a payment entry in the Order API and initialize a session with your provider.

POST /api/v1/checkout/orders/{orderId}/payments
Host: your-adapter.example.com
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}

Your adapter should:

  1. Fetch the order from the Order API
  2. Retrieve your configuration
  3. Create a payment session with your provider
  4. Create a payment entry in the Order API
  5. Register hooks for cart, shipping, and state changes
  6. Register notifications for order completion
  7. Return session data (HTML snippet, redirect URL, or SDK configuration) to the frontend

Handle Cart Changes

When the cart changes, your registered hook receives a callback. Update your provider's session to reflect the new amounts:

POST /api/v1/callback/orders/{orderId}/payments/{paymentId}/cart-changed
Host: your-adapter.example.com
Content-Type: application/json

{
  "orderId": "...",
  "changes": { ... }
}

Return JSON Patch operations to update the payment amount in the Order API, or return an error if your provider cannot accommodate the change.

Complete Payment

When the customer completes payment through your provider, transition the order through the appropriate states and record the transaction:

POST /api/v0/checkout/orders/{orderId}/payments/{paymentId}/transactions
Host: {slug}.api-se.{environment}.norce.tech/checkout/order
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}
Content-Type: application/json

{
  "type": "authorization",
  "timestamp": "2026-01-15T10:00:00Z",
  "request": { ... },
  "response": { ... }
}

Recording transactions creates an audit trail that helps with debugging and support.

Best Practices

Stateless Design

Never store order data locally. Always fetch the current state from the Order API before performing operations. This ensures consistency and allows your adapter to scale horizontally.

Error Handling

Return appropriate HTTP status codes and include descriptive error messages:

StatusUsage
200 OKSuccessful operation
400 Bad RequestInvalid input
404 Not FoundOrder or payment not found
409 ConflictState conflict (e.g., order already completed)
422 Unprocessable EntityValidation failed
502 Bad GatewayExternal provider unavailable

Idempotency

Design your endpoints to handle duplicate requests safely. Use the payment reference or transaction ID to detect and handle retries without creating duplicate records.

Performance

Hooks block the checkout flow, so keep response times under 2 seconds. Cache configuration data (with appropriate TTL) but always fetch order data fresh.

Security

All endpoints must use HTTPS. Validate webhook signatures from your external provider. Never log sensitive data like API keys or card numbers.

Testing

Test your adapter against the playground environment before deploying to production. The playground environment uses sandbox/test modes for all integrated providers.

EnvironmentURL Pattern
Playground{slug}.api-se.playground.norce.tech
Stage{slug}.api-se.stage.norce.tech
Production{slug}.api-se.norce.tech

Next Steps