03API reference
FFL Checkout
Server-to-server only. Find an FFL near a shopper and send Rollmark the order that was made with it.
FFLs near a ZIP
/checkout/fflsServer-to-server only (no CORS; a request with an Origin or Sec-Fetch-Site header is refused). Takes a
checkout key. The store's plan must include FFL Checkout. Preferred FFLs first, then by distance; the store's
blocked FFLs are left out. This is ATF's monthly list, not a live ATF check.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
ziprequired | query | string | Pattern `^[0-9]{5}$`. |
radius | query | integer | Miles. Default 25 Default 25. 1 to 100. |
limit | query | integer | Default 25. 1 to 50. |
page | query | integer | Default 1. At least 1. |
Responses
Headers: X-Request-Id, X-RateLimit-Remaining
| Field | Type | Description |
|---|---|---|
datarequired | object[] | |
data[].idrequired | string | The 13-character licensee id. |
data[].license_numberrequired | string | |
data[].namerequired | string | |
data[].addressrequired | object | |
data[].address.streetrequired | string | null | Null where the directory hides the street. |
data[].address.cityrequired | string | |
data[].address.staterequired | string | |
data[].address.ziprequired | string | |
data[].phone | string | null | |
data[].license_typerequired | object | |
data[].license_type.coderequired | string | |
data[].license_type.labelrequired | string | |
data[].expiresrequired | string (date) | null | |
data[].distance_miles | number | null | |
data[].claimed | boolean | |
data[].preferredrequired | boolean | |
data[].accepts_transfersrequired | "yes" | "no" | "unknown" | |
data[].transfer_fee | number | null | |
data[].hours | string | null | |
data[].contacts | object[] | |
data[].contacts[].kindrequired | "email" | "phone" | |
data[].contacts[].valuerequired | string | |
data[].contacts[].label | string | |
pagerequired | integer | |
limitrequired | integer | |
totalrequired | integer | |
list_as_ofrequired | string (date) | null |
Example
One FFL
/checkout/ffls/{id}id is the licensee id or a license number written any way. One 404 for every reason (not listed, hidden, a collector, unknown).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string |
Responses
Headers: X-Request-Id
| Field | Type | Description |
|---|---|---|
datarequired | object | |
data.idrequired | string | The 13-character licensee id. |
data.license_numberrequired | string | |
data.namerequired | string | |
data.addressrequired | object | |
data.address.streetrequired | string | null | Null where the directory hides the street. |
data.address.cityrequired | string | |
data.address.staterequired | string | |
data.address.ziprequired | string | |
data.phone | string | null | |
data.license_typerequired | object | |
data.license_type.coderequired | string | |
data.license_type.labelrequired | string | |
data.expiresrequired | string (date) | null | |
data.distance_miles | number | null | |
data.claimed | boolean | |
data.preferredrequired | boolean | |
data.accepts_transfersrequired | "yes" | "no" | "unknown" | |
data.transfer_fee | number | null | |
data.hours | string | null | |
data.contacts | object[] | |
data.contacts[].kindrequired | "email" | "phone" | |
data.contacts[].valuerequired | string | |
data.contacts[].label | string | |
data.statusrequired | "active" | "expired" | "inactive" | |
data.blockedrequired | boolean | |
data.list_as_ofrequired | string (date) | null | |
data.ez_check_urlrequired | string (uri) | |
data.noticerequired | string |
Example
The dealer's preferred FFLs
/checkout/preferredParameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer | Default 50. 1 to 50. |
page | query | integer | Default 1. At least 1. |
Responses
Headers: X-Request-Id
| Field | Type | Description |
|---|---|---|
datarequired | object[] | |
data[].idrequired | string | The 13-character licensee id. |
data[].license_numberrequired | string | |
data[].namerequired | string | |
data[].addressrequired | object | |
data[].address.streetrequired | string | null | Null where the directory hides the street. |
data[].address.cityrequired | string | |
data[].address.staterequired | string | |
data[].address.ziprequired | string | |
data[].phone | string | null | |
data[].license_typerequired | object | |
data[].license_type.coderequired | string | |
data[].license_type.labelrequired | string | |
data[].expiresrequired | string (date) | null | |
data[].distance_miles | number | null | |
data[].claimed | boolean | |
data[].preferredrequired | boolean | |
data[].accepts_transfersrequired | "yes" | "no" | "unknown" | |
data[].transfer_fee | number | null | |
data[].hours | string | null | |
data[].contacts | object[] | |
data[].contacts[].kindrequired | "email" | "phone" | |
data[].contacts[].valuerequired | string | |
data[].contacts[].label | string | |
pagerequired | integer | |
limitrequired | integer | |
totalrequired | integer | |
list_as_ofrequired | string (date) | null |
Example
Send the order a shopper made with a chosen FFL
/checkout/ordersCreates a pending order (or an open, matched one when store_order_number is sent). Idempotent on intake_ref:
the same body again is 200 with Idempotent-Replay: true; a different body is 409 intake_conflict. At most
256 KB. No card data, ever: a field named like card data is 400 card_data_rejected.
Request body
| Field | Type | Description |
|---|---|---|
intake_refrequired | string | Your key for the order (a cart id). Makes the call idempotent. Up to 100 characters. |
store_cart_ref | string | Up to 60 characters. |
store_order_number | string | null | When given Up to 40 characters. |
store_order_ref | string | null | Up to 60 characters. |
dealer_po | string | null | Up to 25 characters. |
shopperrequired | object | |
shopper.namerequired | string | |
shopper.emailrequired | string (email) | |
shopper.phone | string | |
billingrequired | object | |
billing.name | string | |
billing.line1required | string | |
billing.line2 | string | |
billing.cityrequired | string | |
billing.staterequired | string | |
billing.ziprequired | string | |
billing.countryrequired | string | |
shipping | object | |
shipping.name | string | |
shipping.line1required | string | |
shipping.line2 | string | |
shipping.cityrequired | string | |
shipping.staterequired | string | |
shipping.ziprequired | string | |
shipping.countryrequired | string | |
ffl | object | Required when any line ships to the FFL. |
ffl.id | string | |
ffl.license_number | string | |
linesrequired | object[] | 1 to 200 items. |
lines[].sku | string | |
lines[].upc | string | Pattern `^[0-9]{8,14}$`. |
lines[].mpn | string | |
lines[].manufacturer | string | |
lines[].titlerequired | string | |
lines[].quantityrequired | integer | 1 to 10000. |
lines[].unit_price_cents | integer | At least 0. |
lines[].needs_ffl | boolean | A hint. The library decides; a disagreement is flagged |
totals | object | |
totals.currency | string | 3 to 3 characters. |
totals.subtotal_cents | integer | |
totals.shipping_cents | integer | |
totals.tax_cents | integer | |
totals.total_cents | integer |
Responses
Headers: Idempotent-Replay
| Field | Type | Description |
|---|---|---|
datarequired | object | Where an order stands. Never the shopper's details or billing. |
data.idrequired | string (uuid) | |
data.intake_refrequired | string | |
data.statusrequired | "pending" | "open" | "cancelled" | "closed" | |
data.match_staterequired | "unmatched" | "auto" | "manual" | |
data.dealer_po | string | null | |
data.store_order_number | string | null | |
data.cancelled_reason | string | null | |
data.ffl | object | null | The FFL as it was when the shopper chose it. |
data.ffl.id | string | |
data.ffl.license_number | string | |
data.ffl.name | string | |
data.ffl.phone | string | null | |
data.ffl.street | string | null | |
data.ffl.city | string | |
data.ffl.state | string | |
data.ffl.zip | string | |
data.ffl.list_as_of | string | null | |
data.linesrequired | object[] | |
data.lines[].line_norequired | integer | |
data.lines[].sku | string | null | |
data.lines[].titlerequired | string | |
data.lines[].quantityrequired | integer | |
data.lines[].ships_torequired | "ffl" | "customer" | |
data.lines[].ship_reasonrequired | "firearm" | "receiver" | "library_not_firearm" | "store_hint" | "staff_override" | |
data.lines[].flagged | string | null |
|
data.lines[].product_key | string | null | |
data.received_atrequired | string (date-time) | |
data.updated_atrequired | string (date-time) |
Example
Where an order stands
/checkout/orders/{id}id is the order id or ref:<intake_ref>. Never returns the shopper's details.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string |
Responses
| Field | Type | Description |
|---|---|---|
datarequired | object | Where an order stands. Never the shopper's details or billing. |
data.idrequired | string (uuid) | |
data.intake_refrequired | string | |
data.statusrequired | "pending" | "open" | "cancelled" | "closed" | |
data.match_staterequired | "unmatched" | "auto" | "manual" | |
data.dealer_po | string | null | |
data.store_order_number | string | null | |
data.cancelled_reason | string | null | |
data.ffl | object | null | The FFL as it was when the shopper chose it. |
data.ffl.id | string | |
data.ffl.license_number | string | |
data.ffl.name | string | |
data.ffl.phone | string | null | |
data.ffl.street | string | null | |
data.ffl.city | string | |
data.ffl.state | string | |
data.ffl.zip | string | |
data.ffl.list_as_of | string | null | |
data.linesrequired | object[] | |
data.lines[].line_norequired | integer | |
data.lines[].sku | string | null | |
data.lines[].titlerequired | string | |
data.lines[].quantityrequired | integer | |
data.lines[].ships_torequired | "ffl" | "customer" | |
data.lines[].ship_reasonrequired | "firearm" | "receiver" | "library_not_firearm" | "store_hint" | "staff_override" | |
data.lines[].flagged | string | null |
|
data.lines[].product_key | string | null | |
data.received_atrequired | string (date-time) | |
data.updated_atrequired | string (date-time) |
Example
The store's own order now exists
/checkout/orders/{id}/matchMakes a pending order open. The same number again is 200; another number is 409 already_matched; an order staff cancelled is 409 order_cancelled.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string |
Request body
| Field | Type | Description |
|---|---|---|
store_order_numberrequired | string | Up to 40 characters. |
store_order_ref | string | Up to 60 characters. |
Responses
| Field | Type | Description |
|---|---|---|
datarequired | object | Where an order stands. Never the shopper's details or billing. |
data.idrequired | string (uuid) | |
data.intake_refrequired | string | |
data.statusrequired | "pending" | "open" | "cancelled" | "closed" | |
data.match_staterequired | "unmatched" | "auto" | "manual" | |
data.dealer_po | string | null | |
data.store_order_number | string | null | |
data.cancelled_reason | string | null | |
data.ffl | object | null | The FFL as it was when the shopper chose it. |
data.ffl.id | string | |
data.ffl.license_number | string | |
data.ffl.name | string | |
data.ffl.phone | string | null | |
data.ffl.street | string | null | |
data.ffl.city | string | |
data.ffl.state | string | |
data.ffl.zip | string | |
data.ffl.list_as_of | string | null | |
data.linesrequired | object[] | |
data.lines[].line_norequired | integer | |
data.lines[].sku | string | null | |
data.lines[].titlerequired | string | |
data.lines[].quantityrequired | integer | |
data.lines[].ships_torequired | "ffl" | "customer" | |
data.lines[].ship_reasonrequired | "firearm" | "receiver" | "library_not_firearm" | "store_hint" | "staff_override" | |
data.lines[].flagged | string | null |
|
data.lines[].product_key | string | null | |
data.received_atrequired | string (date-time) | |
data.updated_atrequired | string (date-time) |