Docs
Firmly Agentic Commerce
Set theme to dark (⇧+D)

Get Card Art

GET https://api.firmly.work/api/v1/wallets/agentic-pay/card-art/{token}

​​ Overview

Returns the card art image (the visual card image from the issuing bank) for a card enrolled via Agentic Pay. The URL is returned in the card_art.url field of the enroll response and in the Wallet Complete Order response (where it appears under payment_summary.card_art). No authentication header is needed — the HMAC-signed token in the URL path serves as authorization.

​​ Authentication

This endpoint requires no authentication. The token path parameter contains an HMAC-signed payload that serves as authorization.

​​ Path Parameters

  • token (string, required) — HMAC-signed compact token in the format <base64url-payload>.<signature>. Contains the network, image locator, and expiry. Generated by Firmly during enrollment.

​​ Response

The response is binary image data with the following headers:

  • content-type (string) — image/png or image/jpeg depending on the card art source

  • cache-control (string) — public, max-age=86400, immutable

  • x-firmly-card-art-source (string) — Source identifier for the card art image

​​ Card Art Object Shape

The card_art object returned by /enroll has this shape. Destinations should persist it from the initial enrollment for use in the saved-card UI:

  • card_art.network (string) — Card network (visa, mastercard, or discover)

  • card_art.url (string) — Full URL to this card-art endpoint with the signed token

  • card_art.background_color (string) — Hex color code for the card background (e.g., #1A1F71)

  • card_art.foreground_color (string) — Hex color code for the card foreground text (e.g., #FFFFFF)

  • card_art.descriptor (string) — Issuing bank descriptor (e.g., "Test Bank 2")

​​ Code Examples


# Use the URL directly from the enroll or complete response
curl -o card-art.png \
"https://api.firmly.work/api/v1/wallets/agentic-pay/card-art/eyJuIjoiVklTQSIsImx..."

// The card_art.url from the enroll/complete response can be used directly
const enrollResponse = await enroll(cardDetails);
const { card_art } = enrollResponse;
// Drop directly into an img tag
const img = document.createElement('img');
img.src = card_art.url;
// Or fetch the image programmatically
const response = await fetch(card_art.url);
const contentType = response.headers.get('content-type');
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);

import requests
# Use the URL from the enroll/complete response
card_art_url = enroll_response["card_art"]["url"]
response = requests.get(card_art_url)
content_type = response.headers["content-type"]
# Save to file
extension = "png" if "png" in content_type else "jpeg"
with open(f"card-art.{extension}", "wb") as f:
f.write(response.content)

​​ Response Example


{
"card_art": {
"network": "visa",
"url": "https://api.firmly.work/api/v1/wallets/agentic-pay/card-art/<signed-token>",
"background_color": "#1A1A2E",
"foreground_color": "#FFFFFF",
"descriptor": "Test Bank 2"
}
}

​​ How the Proxy Works

The card-art endpoint acts as a secure proxy between the destination and the card network’s asset service. Firmly fetches the image using its own network credentials, so destinations never need direct access to network asset APIs. The token has a default TTL of 1 hour.

​​ Error Responses

Errors are returned as JSON, not as image data.

Error Code Status Description
BadRequest 400 Malformed token or locator host not allowed
Unauthorized 401 Signature invalid or token expired
PaymentMethodNotAvailable 409 Card art not found at the network (e.g., nonexistent Visa GUID)
400 - Bad Request

{
"code": 400,
"error": "BadRequest",
"description": "Malformed token or locator host not allowed"
}
401 - Unauthorized

{
"code": 401,
"error": "Unauthorized",
"description": "Signature invalid or token expired"
}
409 - Card Art Not Found

{
"code": 409,
"error": "PaymentMethodNotAvailable",
"description": "Card art not found at the network"
}

  • Enroll Card — Enroll a card and receive the card_art object in the response
  • Intent Challenge — Complete a payment-level challenge for the intent