Skip to content
TilloTech Docs

Amilon Processor and API

This reference describes the active asynchronous Amilon issuer and the deprecated synchronous implementation that can appear in historical data. It covers contract and denomination resolution, request and response mapping, queue states, duplicate risks, audit evidence, operational commands, and support boundaries.

Processor modes and scope

AmilonAsyncProcessor is the active queued issuer. The async issuer migration marks it as asynchronous and moves existing Amilon brands from the legacy issuer. AmilonProcessor is marked deprecated and is no longer expected to be returned to.

CapabilityAsync issuerLegacy sync issuer
Create callPOST /orders/create/{contractCode}Same provider create operation through the legacy API wrapper
Voucher retrievalGET orders/{processorReference}/complete/No separate complete retrieval; reads Vouchers[0] from create response
Processor referenceResponse ExternalOrderIdResponse ExternalOrderId
Completion ruleCardCode is presentCreate response contains the voucher data expected by the sync implementation
CancellationNot implementedNot implemented in the inspected legacy class
BalanceContract-float lookup, not card balanceNo customer-card balance operation in the inspected processors
Vaultuses_vault is false in the async issuer migrationLegacy issuer also does not use a vault

Async lifecycle

  1. A sale supplies a partner, currency, brand, and face value. The API resolves a partner-specific contract when configured and otherwise uses the global contract for that currency.
  2. The API normalizes the face value and looks up the brand attribute amilon-product-code-<normalized amount>. Product-code mappings are cached per brand for one hour.
  3. The async create payload contains the sale UUID as ExternalOrderId and one OrderRows item with the mapped ProductId and Quantity 1.
  4. POST /orders/create/{contractCode} returns an Amilon payload. The response object maps ExternalOrderId as the processor reference. If the first voucher has a CardCode, the application card is successful immediately; otherwise it is pending.
  5. A pending create is requeued by AsyncProcessRequest; when an existing-order exception supplies CODE_ORDER_EXISTS, the job instead schedules AsyncFetchCode. The retrieval job calls GET orders/{processorReference}/complete/ and maps the returned voucher. The complete URL includes an empty client-auth segment and therefore ends with /complete/.
  6. A voucher with a code is stored with its normalized amount, code, and VoucherLink, and the sale becomes successful. A voucher without a code remains pending and is retried by the retrieval job.

An accepted order and a completed voucher are different provider states. The payload may contain OrderStatus, but the response mapper uses the presence of Vouchers[0].CardCode as the application completion test.

!WARNING Do not manually create a replacement order while the original ExternalOrderId is unresolved. A create request can be accepted even when the code is not yet available, and another create request can produce a duplicate provider order or an “order already exists” response.

Redacted request and response examples

The active create request is JSON. Identifiers and product codes below are synthetic.

json
{
  "ExternalOrderId": "sale-uuid-example",
  "OrderRows": [
    {
      "ProductId": "product-code-example",
      "Quantity": 1
    }
  ]
}

The tests use the following response shape. Voucher code and link values are redacted here:

json
{
  "ExternalOrderId": "external-order-example",
  "Vouchers": [
    {
      "Amount": "25.00",
      "CardCode": "[REDACTED]",
      "VoucherLink": "https://provider.example/voucher/redacted"
    }
  ],
  "OrderStatus": "Completed"
}

The authentication request is form encoded and includes client_id, client_secret, username, password, and grant_type=password. Do not copy credentials, voucher codes, PINs, customer details, or live voucher links into documentation or support tickets.

Response mapping and validation

AmilonGiftCard::translateApiResponse() reads only the first item in Vouchers and maps these fields:

Amilon fieldApplication fieldRule
ExternalOrderIdprocessorReferenceIdentifies the provider order and is retained for retrieval
Vouchers[0].AmountfaceValueNormalized and cast to a float
Vouchers[0].CardCodecodePresence makes the application card successful
Vouchers[0].VoucherLinkthirdPartyUrlStored as the provider voucher URL

The parser requires the Vouchers array and its first item. Missing structural fields raise AmilonException with CODE_REPEAT_REQUEST, and the async job can retry the request. A valid structure with a missing or empty CardCode produces a pending card instead. The parser does not use Pin, ValidityEndDate, OrderStatus, GrossAmount, or NetAmount when creating the async application card.

The HTTP client decodes JSON responses and rejects a response that cannot be represented as an array. Guzzle failures are wrapped by AmilonException; timeout messages receive a gateway-timeout code, the known retry messages receive CODE_REPEAT_REQUEST, and the exact provider “order already exists” message receives CODE_ORDER_EXISTS.

Provider states, retries, and duplicate risk

ConditionApplication handlingInvestigation meaning
Vouchers[0].CardCode presentMark success and complete the saleVoucher details are available
Voucher structure valid but CardCode emptyMark pending; retrieval can be queued againProvider order exists, but code is not available in the payload
Missing Vouchers or malformed payloadRaise repeatable AmilonException; audit the responseCheck provider payload shape and retry history
Timeout or retryable provider messageAsync job repeats the requestDetermine whether the original create was accepted before retrying
Exact “order with Id … already exists!” provider errorMap to CODE_ORDER_EXISTS; AsyncProcessRequest schedules AsyncFetchCodeUse the original external order ID and retrieve it; do not create a replacement
Other create/retrieve exceptionRestore the sale to a retryable state or fail the job according to queue handlingCheck exception code, response body, and job history

AmilonAsyncProcessor does not define a processor-local maximum retry count. AsyncProcessRequest repeats create errors with CODE_REPEAT_REQUEST; AsyncFetchCode repeats retrieval errors with the same code and requeues pending cards using retrieval delay metadata. Queue configuration and job history are therefore part of the retry investigation.

Audit and reconciliation fields

Compare safe identifiers and metadata across the sale, processor interaction log, and provider response:

Local or audit fieldAmilon value to compare
Sale UUIDCreate ExternalOrderId
Partner and currencyResolved partner/global contract and currency code
ContractcontractCode in POST /orders/create/{contractCode}; configuration calls this value a contract code
Face valueNormalized denomination used in the brand-attribute lookup and voucher Amount
Product mappingOrderRows[0].ProductId and amilon-product-code-<amount>
QuantityOrderRows[0].Quantity, normally 1
Processor referenceResponse ExternalOrderId, stored as processor_ref
CompletionPresence of Vouchers[0].CardCode and VoucherLink; compare presence or a redacted fingerprint, not raw values
Time and retry contextSale timestamps, request/retrieval attempt history, and exception code

The async processor stores its generated request, provider response, and exception response body in processor interaction audit records. Authentication requests and responses are also initialized against the sale UUID. The unit tests assert one request and one response record for successful create and retrieval paths, and assert that an invalid response body is retained for investigation.

Settings and brand mappings

config/amilon.php reads these settings:

SettingEnvironment variablePurpose
SSO URLAMILON_ENVIRONMENT_SSO_URLAuthentication base URL; token path appends /connect/token
Web API URLAMILON_ENVIRONMENT_WEB_API_URLAPI base used with /b2bwebapi/{AMILON_API_VERSION}
API versionAMILON_API_VERSIONVersion segment for the web API base URI
CredentialsAMILON_CLIENT_ID, AMILON_CLIENT_SECRET, AMILON_USERNAME, AMILON_PASSWORDOAuth password-grant authentication
Global contract codesAMILON_CONTRACT_ID, AMILON_CONTRACT_ID_GBP, AMILON_CONTRACT_ID_CHF, AMILON_CONTRACT_ID_PLNContract per configured global currency
Partner contract overridesAMILON_CONTRACT_ID_EDENRED_ITALY, AMILON_CONTRACT_ID_DIGGECARD_EDENRED_ITALYEUR contract overrides for configured partner slugs
Float monitoringAMILON_AVAILABLE_FLOAT_ALERT_ENABLED and AMILON_AVAILABLE_FLOAT_ALERT_LIMIT_*Enable alerts and set per-currency limits
Catalogue cultureAMILON_BRAND_INFO_CULTURE_IT_IT, AMILON_BRAND_INFO_CULTURE_EN_UKCulture passed to product and catalogue calls
Notification recipientsFINANCE_EMAIL_ADDRESS, TECHTEAM_EMAIL_ADDRESSCommand notification configuration

AMILON_API_URL is present as a legacy endpoint configuration value and is annotated as unused in config/amilon.php. The active API builds its base URI from AMILON_ENVIRONMENT_WEB_API_URL and AMILON_API_VERSION.

Each enabled brand needs amilon-product-code-<normalized amount> for every sellable fixed denomination. The stored attribute value is sent as ProductId. A missing attribute raises a missing-denomination-code exception before the provider order is created. The one-hour product-code cache means a mapping change may require cache expiry or invalidation before it is observed.

API operations and operational tools

OperationEndpoint or commandUse
AuthenticatePOST {SSO_URL}/connect/tokenForm-encoded password grant; token is cached with a 30-second expiry reduction
Create orderPOST /b2bwebapi/{version}/orders/create/{contractCode}Create a voucher order with ExternalOrderId and OrderRows
Complete orderGET /b2bwebapi/{version}/orders/{processorReference}/complete/Retrieve voucher details for an existing order
Available productsGET /b2bwebapi/{version}/contracts/{contractId}/{culture}/productsRead active contract products and prices
Complete catalogueGET /b2bwebapi/{version}/contracts/{contractId}/{culture}/products/completeRetrieve detailed product and retailer data
Contract informationGET /b2bwebapi/{version}/contracts/{contractId}Read contract balance data for float checks
Float checkphp artisan rewardcloud:check-amilon-available-floatEmail alerts when configured contract float is below its limit; supports --no-send and --override-recipient-email
Denomination availabilityphp artisan rewardcloud:check-amilon-brand-denominations-availabilityUpdate brand-denomination availability from global contract product prices
Brand information exportphp artisan report:amilon-brands-information-exportExport retailer/products information; supports --no-send and --override-recipient-email

The denomination availability command checks global currency contracts and applies the resulting product prices to matching brands. Partner-specific contracts use the same product codes as the corresponding global contract according to the service comment, so a change still needs to be checked against the affected partner catalogue.

Investigation checklist

  1. Record the sale UUID, partner slug, brand slug, currency, normalized face value, sale status, and processor_ref.
  2. Resolve the contract mapping: check the partner override first, then the global currency contract, and confirm that the configured value is a contract code.
  3. Check amilon-product-code-<normalized amount> and confirm its cached value matches the current provider product code.
  4. Compare the audited request’s ExternalOrderId, ProductId, and quantity with the sale and brand mapping.
  5. Check the create response for ExternalOrderId, Vouchers, Amount, CardCode, VoucherLink, and OrderStatus; treat CardCode presence, not OrderStatus alone, as completion evidence.
  6. If retrieval is pending, call history and job records should show orders/{processorReference}/complete/ attempts and retrieval delay metadata.
  7. If a duplicate error appears, stop replacement orders and search by the original external order ID before scheduling retrieval.
  8. Check authentication audit entries without exposing credentials, then compare provider status, exception code, timestamps, and response body shape.
  9. For float or catalogue issues, run the relevant command in the correct environment and compare the contract, culture, product code, price, and brand-denomination status.

Limitations and support

The async processor does not implement customer-card cancellation or card-balance lookup. retrieveContractBalance() and the available-float command report processor contract float, not the remaining value of an issued voucher. The async issuer migration sets uses_vault to false.

Escalations should include the sale UUID, external order ID, contract context, product mapping, timestamps, safe audit comparisons, and exception codes. Do not include credentials, raw CardCode, PIN values, customer details, or live VoucherLink values unless the approved support process explicitly requires protected data.

  • app/Processors/Amilon/AmilonAsyncProcessor.php — async create, retrieval, status mapping, and audit interaction handling.
  • app/Processors/Amilon/AmilonApi.php — authentication, contract selection, product-code lookup, order, retrieval, catalogue, and float calls.
  • app/Processors/Amilon/ResponseObjects/AmilonGiftCard.php — response validation and field mapping.
  • app/Processors/Amilon/Exception/AmilonException.php — retry, timeout, duplicate-order, and malformed-response classifications.
  • app/Processors/AmilonProcessor.php — deprecated synchronous create-response behavior.
  • config/amilon.php — URLs, credentials, contract codes, cultures, and alert configuration.
  • app/Jobs/AsyncProcessRequest.php and app/Jobs/AsyncFetchCode.php — pending and retry queue transitions.
  • app/Console/Commands/CheckAmilonAvailableFloat.php — contract-float alert command.
  • app/Console/Commands/CheckAmilonBrandDenominationsAvailability.php — product availability and denomination status command.
  • app/Console/Commands/GenerateAmilonBrandsInformationExport.php — catalogue export command.
  • tests/Unit/Processors/Amilon/AmilonAsyncProcessorTest.php — async mapping, pending/error, and audit scenarios.
  • tests/Unit/Processors/Api/Amilon/AmilonApiTest.php — request paths, payload shape, contracts, catalogue, and response mapping examples.
  • database/migrations/2021_09_30_161102_rcc_8962_add_amilon_async_processor.php — async issuer, support contact, and wiki metadata.
  • database/migrations/2021_11_01_133415_r_c_c-9194-move-amilon-brands-over-from-sy.php — migration of legacy Amilon brands to async.