Diggecard processor reference
This guide describes the implemented Diggecard issuance and account-balance integration, including brand mapping, response validation, audit evidence, and operational risks. Examples show request and response shapes with credentials, URLs, identifiers, and card data redacted.
Processing model
Diggecard is a synchronous processor with a non-vault issuer record. The processor creates one digital gift card through the giftcard endpoint and maps either a claim URL or card number and PIN from the response.
| Property | Implemented behaviour |
|---|---|
| Issuer | Diggecard |
| Asynchronous processing | Disabled in the issuer migration |
| Processor types | SKU per denomination for fixed brands and SKU per product for open-value brands |
| Issuance endpoint | POST {DIGGECARD_ENDPOINT}giftcard |
| Balance endpoint | GET {DIGGECARD_ENDPOINT}account_balance |
| Accepted success state | HTTP 200 and giftCard.status of active or ACTIVE |
| Delivery mapping | Claim URL when both card number and PIN are empty; otherwise card number, PIN, and claim URL |
| Cancellation, reissue, and top-up | Not implemented by this processor's request builder and response parser |
Issuance lifecycle
- The synchronous processor receives the brand, partner, face value, currency, and internal sale record.
- For a fixed-denomination brand, it looks up
diggecard-sku-{amount}. For an open-value brand, it looks updiggecard-sku. - The sale UUID becomes both
auditNumberandpurchaseOrderNumber. - The processor posts the request to the
giftcardendpoint using Basic authentication and a JSON body. - The raw response is written to the processor interaction audit. A non-
200response is treated as an external processor failure. - The JSON response must contain a
giftCardobject whosestatusisactiveorACTIVE. - If
cardExpiryis absent, the application generates an expiry using the brand'sexpiry-monthsattribute. If bothcardNumberandcardPinare empty, the claim URL is used for delivery; otherwise a non-empty card number is required for code delivery. - The resulting card uses
transactionIdas the processor reference. The audit record is completed only after response parsing and card creation succeed.
HTTP contract
The endpoint is DIGGECARD_ENDPOINT with giftcard appended. The client sends Accept: application/json, Content-Type: application/json, and an Authorization header of the form Basic <base64-redacted-credentials>. The request timeout is 20 seconds.
Gift-card request
The request body contains the internal sale UUID in both transaction fields:
{
"auditNumber": "<sale-uuid>",
"purchaseOrderNumber": "<sale-uuid>",
"vendorCode": "<redacted-brand-code>",
"cardAmount": "<face-value>",
"currency": "GBP",
"delivery": {
"deliveryType": "api"
}
}
The repository does not document a provider idempotency key separate from these transaction fields. auditNumber and purchaseOrderNumber are correlation values generated from the sale UUID, not proof that a repeated request is safe.
Gift-card response
A URL-delivery response in the tests has empty card number and PIN values. A code-delivery response has a card number, PIN, and claim URL. Both use the following relevant shape:
{
"transactionId": "<provider-transaction-id>",
"giftCard": {
"status": "ACTIVE",
"cardNumber": "<redacted-or-empty>",
"cardPin": "<redacted-or-empty>",
"claimUrl": "<redacted-claim-url>",
"cardExpiry": "<provider-expiry-or-null>"
}
}
Do not copy cardNumber, cardPin, claim URLs, or complete provider responses into tickets or chat. The examples are structural and are not reusable card data.
Response mapping and validation
The parser first requires a JSON object. For a create request it then validates giftCard.status as a required string with value active or ACTIVE.
| Response path | Rule or fallback | Internal card field |
|---|---|---|
transactionId | Converted to a string | processor_reference |
giftCard.status | Required; must be active or ACTIVE | Determines whether parsing may continue |
giftCard.cardExpiry | Used when present | Expiration date |
Missing giftCard.cardExpiry | Generated from the brand expiry-months attribute | Expiration date |
Empty giftCard.cardNumber and giftCard.cardPin | Treated as URL delivery | Empty code and PIN; claimUrl becomes the URL |
| Non-empty card data | cardNumber must be non-empty | Code, PIN, and claimUrl are mapped |
An invalid JSON body, missing or inactive status, or an empty card number in a response that is not the URL-only shape produces an external processor error. The parser does not define meanings for provider statuses other than the two accepted active spellings. For example, the feature test uses PROCESSING as a failure case; it must not be treated as a completed sale.
Provider states and error handling
The application distinguishes the following observable states:
| Observable state | Application behaviour |
|---|---|
HTTP 200 with active gift card | Parse and complete the card |
HTTP 200 with another status | Reject with the message that the gift card was not active |
HTTP non-200 | Log the response and raise an external processor error |
HTTP 400 with an errors array | Preserve the response in the audit and expose a generic external error to the API caller |
| Connection, timeout, or request exception | Convert to an external processor error after logging available details |
| Missing vendor code | Fail before sending because brand mapping is incomplete |
| Missing partner credentials | Fail while generating the Basic authorization header |
Provider error-code semantics are not enumerated in the implementation. The errors payload and HTTP status are evidence, not a documented state machine.
Retry and duplicate risks
SyncProcessorCommon defaults maxAttempts to 1, and DiggecardProcessor does not override it. Issuance therefore has no automatic retry in this integration. A timeout or connection failure after the provider receives the giftcard request leaves the outcome unknown; submitting the same sale again can create a second card unless the provider confirms idempotency or reconciles the original auditNumber and purchaseOrderNumber.
Do not retry an uncertain issuance blindly. First compare the audit request and response, search for a provider transactionId, and escalate the sale UUID and timestamps to the internal processor owner or Diggecard account team. A non-active response is not evidence that no card was created; it only means this parser did not complete the sale.
Authentication, settings, and brand mappings
config/diggecard.php defines these environment-backed values:
| Configuration area | Values |
|---|---|
| Global account | DIGGECARD_USERNAME, DIGGECARD_PASSWORD, and DIGGECARD_ENDPOINT |
| Balance alerts | Enable flag, GBP and EUR thresholds, and recipient setting |
| Partner accounts | reward-gateway, giftcloud, and epay-youchoose, each with username, password, and useOwnAccount |
For reward-relationship partners, the processor uses the global account unless the partner configuration explicitly selects its own account. Otherwise it uses the configured partner credentials when both are present. The balance operation falls back to the global account. Credentials must remain in environment configuration and must be redacted from operational evidence.
Brand attributes
The vendor-code lookup is database-backed:
| Brand mode | Attribute read | Required setup |
|---|---|---|
| Fixed denominations | diggecard-sku-{amount} | One vendor code for each supported amount |
| Open value | diggecard-sku | One product vendor code plus the brand's open-value limits |
| Expiry fallback | expiry-months | Used only when Diggecard omits cardExpiry |
The migrations provide these onboarding facts:
- River Island was moved to Diggecard as open value with limits of
2to250. - The Body Shop, TK Maxx, Arsenal, River Island, HomeSense, National Trust, and Eurostar were configured as open-value examples with limits recorded in the onboarding migration.
- ASK Italian, Waterstones, Zizzi, Hobbycraft, Jojo Maman Bébé, and Virgin Wines were configured as fixed-denomination examples.
- IKEA UK was configured as URL-only with fixed GBP denominations of
5,10,15,20,25,50,75,100,150,200,250,500, and1000in the onboarding migration. - Mango was configured as URL-only with fixed denominations of
25and50GBP. Its historical vendor-code migration records denomination codes for20,25,50,75,100,150, and200. - A later migration moved vendor codes into brand attributes. The current processor reads those attributes rather than a
diggecard.brandsconfiguration block. - The November 2025 migration removed
returnsUrlattributes. The current parser uses the returnedclaimUrlfor the URL-only response shape and does not readreturnsUrl.
The onboarding migrations are historical records, not a guarantee that every listed brand is currently active. Verify the live brand row, issuer, delivery method, denomination, and attribute before issuing.
Account-balance operation and command
DiggecardProcessor::getAvailableCreditLimit() sends a credentialed GET request to account_balance. It requires HTTP 200 and returns the raw response body. The implementation does not validate the shape in this method; the scheduled command decodes the body and reads accountBalances.
The command is:
rewardcloud:check-available-diggecard-credit-limit
It exits with failure without calling Diggecard when DIGGECARD_LOW_CREDIT_ALERT_ENABLED is false. With alerts enabled, it records a FileExportCommand, reads each returned account balance, applies the configured GBP or EUR threshold, and sends the low-balance alert only in production or sandbox unless --override-recipient-email is supplied. --no-send generates the report path without sending email. The command has no option to change the provider account or threshold.
Audit comparison fields
The processor writes the request and response to ProcessorInteractionAuditLog and also maintains the normal processor audit record. Compare the following values without exposing secrets or card data:
| Evidence | Fields to compare |
|---|---|
| Internal sale | Sale UUID, partner, brand, face value, currency, delivery method, and request timestamp |
| Gift-card request | auditNumber, purchaseOrderNumber, vendorCode, cardAmount, currency, and delivery.deliveryType |
| Gift-card response | HTTP status, transactionId, giftCard.status, expiry presence, and whether the URL-only or code shape was returned |
| Completed card | Processor reference, delivery URL presence, expiry, and completion state |
| Error path | HTTP status/reason, provider errors or error description, exception log message, and attempt number |
| Balance check | Command run, account-balance currency and amount, threshold, environment, recipient mode, and --no-send state |
The audit model encrypts stored content and supports redaction when a redactor is attached. Support extracts should still be manually checked before sharing; encryption is not a reason to publish live voucher or card values.
Investigation checklist
- Confirm the sale UUID, partner slug, brand slug, face value, currency, and requested delivery method.
- Confirm whether the brand is fixed or open value and check the exact
diggecard-sku-{amount}ordiggecard-skuattribute. - Confirm the issuer is Diggecard and that the requested delivery method is enabled for the brand and partner.
- Check partner financial relationship and the effective credential source: global account or partner account.
- Compare the redacted request fields, especially both transaction fields, vendor code, amount, and currency.
- Check the HTTP status and response body shape. An active status must be exactly
activeorACTIVE. - If the response is URL-only, verify that both card number and PIN are empty and that
claimUrlis present. If it is code delivery, verify thatcardNumberis non-empty. - Check whether
cardExpirywas returned or generated from the brandexpiry-monthsattribute. - For an uncertain timeout, search the audit for
transactionIdand do not issue a replacement until the original outcome is reconciled. - For a balance alert, check the command log,
accountBalances, currency threshold, environment, and recipient override; do not include credentials or balances in an external ticket unless required and approved. - Escalate with the sale UUID, provider transaction reference if known, vendor code, UTC timestamps, HTTP status, and redacted audit excerpts.
Limitations and support contacts
The repository implements synchronous issuance and a balance check, but it does not provide a Diggecard status/reconciliation endpoint, cancellation flow, retry-safe idempotency mechanism, or named provider support contact. The parser does not document provider lifecycle states beyond an accepted active status. Escalate unresolved issuance and balance issues through the internal processor owner or Diggecard account team using the evidence in the checklist.
Related code
app/Processors/DiggecardProcessor.php— issuance, response parsing, authentication selection, expiry fallback, and balance request.app/Exceptions/Diggecard/DiggecardException.php— Diggecard external error type.app/Processors/SyncProcessorCommon.php— synchronous request lifecycle, audit completion, and default attempt count.config/diggecard.php— global, partner, and balance-alert settings.app/Console/Commands/CheckAvailableDiggecardCreditLimit.php— account-balance command and alert handling.app/ProcessorInteractionAuditLog.php— encrypted processor request and response audit records.database/migrations/2023_05_09_093426_qrf-733_move_diggecard_vendor_codes_into_brand_attributes.php— migration of vendor codes into brand attributes.database/migrations/2023_05_09_110643_qrf-733_update_diggecard_processor_type.php— fixed and open processor types.database/migrations/2025_11_19_132500_rcc_16844_remove_diggecard_returnsUrl_attributes.php— removal of obsolete URL attributes.tests/Feature/Processors/DiggecardProcessorTest.php— URL and code delivery, audit, error, and status validation cases.