This API is designed for fulfilling shop POS systems to receive and manage incoming GetBloomDirect orders.
Supported v1 Workflow
PENDING_ACCEPTANCE
├─ Accept → ACCEPTED → Delivered → COMPLETED
└─ Decline → DECLINEDWhat v1 POS integrations should support:
Not included in v1
Money Format
GetBloomDirect stores monetary values internally in cents, but the POS API returns dollar amounts as JSON numbers in USD.
Example: 50 means $50.00, and 59.99 means $59.99.
Decline Reasons
If declineReason = "OTHER", then declineMessage is required.
Example:
{
"declineReason": "OTHER",
"declineMessage": "We are closing early today"
}All external v1 API requests must include your shop's API key.
API key header
x-api-key: YOUR_API_KEY
Bearer authorization
Authorization: Bearer YOUR_API_KEY
Use one authentication method per request. The examples in this guide use the x-api-key header.
You can generate and manage your API key from your GetBloomDirect dashboard under POS API Access.
Only Pro shops can use the external POS API. If your subscription becomes inactive, API access will stop until Pro access is restored.
/api/external/v1/ordersRetrieve incoming orders assigned to your fulfilling shop. Use the optional since parameter to return orders updated after a specific timestamp, and limit to control the number of results.
{
"x-api-key": "YOUR_API_KEY"
}curl -X GET "https://www.getbloomdirect.com/api/external/v1/orders?since=2026-08-05T12:00:00.000Z&limit=100" \
-H "x-api-key: YOUR_API_KEY"{
"success": true,
"data": {
"orders": [
{
"id": "68935f106a9e3d72b872a101",
"orderNumber": "1001",
"status": "PENDING_ACCEPTANCE",
"decline": {
"reason": "",
"message": ""
},
"recipient": {
"fullName": "Jane Doe",
"address": "123 Main St",
"apt": "Apt 4B",
"city": "Buffalo",
"state": "NY",
"zip": "14201",
"phone": "555-123-4567",
"email": "jane@example.com",
"company": "Acme Corp",
"message": "Happy Birthday!"
},
"customer": {
"fullName": "John Smith",
"email": "john@example.com",
"phone": "555-987-6543"
},
"products": [
{
"name": "Red Roses",
"description": "Dozen premium roses",
"photo": "https://cdn.getbloomdirect.com/products/roses.jpg",
"qty": 1,
"taxable": true,
"price": 59.99
}
],
"totals": {
"currency": "USD",
"productsSubtotal": 59.99,
"deliveryFee": 10,
"originatingFee": 0,
"tax": 4.8,
"orderTotal": 74.79,
"fulfillmentAmount": 69.99
},
"delivery": {
"date": "2026-08-08T00:00:00.000Z",
"window": {
"type": "specific",
"from": "09:00",
"to": "13:00"
},
"instructions": "Leave at front desk"
},
"paidAt": null,
"timestamps": {
"created": "2026-08-05T12:05:00.000Z",
"accepted": null,
"declined": null,
"completed": null,
"updated": "2026-08-05T12:05:00.000Z"
}
}
]
},
"meta": {
"timestamp": "2026-08-06T13:30:00.000Z",
"version": "1.0"
}
}Optional query parameters
since: ISO 8601 timestamp. Returns orders updated after this time.limit: Positive whole number. Defaults to 100 and has a maximum of 250.GET /api/external/v1/orders?since=2026-07-15T12:00:00.000Z&limit=100
The Orders endpoint and each order-action endpoint return the same normalized order object.
Delivery window
anytime: no specific delivery window was requested. The from and to values are empty strings.specific: both values contain 24-hour HH:mm times.Decline details
For non-declined orders, decline.reason and decline.message are empty strings. For declined orders, they contain the saved decline details.
Monetary totals
All monetary values are returned as USD numbers, not integer cents.
/api/external/v1/orders/:id/acceptAccept an incoming order.
{
"x-api-key": "YOUR_API_KEY"
}curl -X POST "https://www.getbloomdirect.com/api/external/v1/orders/68935f106a9e3d72b872a101/accept" \
-H "x-api-key: YOUR_API_KEY"{
"success": true,
"data": {
"order": {
"id": "68935f106a9e3d72b872a101",
"orderNumber": "1001",
"status": "ACCEPTED",
"decline": {
"reason": "",
"message": ""
},
"recipient": {
"fullName": "Jane Doe",
"address": "123 Main St",
"apt": "Apt 4B",
"city": "Buffalo",
"state": "NY",
"zip": "14201",
"phone": "555-123-4567",
"email": "jane@example.com",
"company": "Acme Corp",
"message": "Happy Birthday!"
},
"customer": {
"fullName": "John Smith",
"email": "john@example.com",
"phone": "555-987-6543"
},
"products": [
{
"name": "Red Roses",
"description": "Dozen premium roses",
"photo": "https://cdn.getbloomdirect.com/products/roses.jpg",
"qty": 1,
"taxable": true,
"price": 59.99
}
],
"totals": {
"currency": "USD",
"productsSubtotal": 59.99,
"deliveryFee": 10,
"originatingFee": 0,
"tax": 4.8,
"orderTotal": 74.79,
"fulfillmentAmount": 69.99
},
"delivery": {
"date": "2026-08-08T00:00:00.000Z",
"window": {
"type": "specific",
"from": "09:00",
"to": "13:00"
},
"instructions": "Leave at front desk"
},
"paidAt": null,
"timestamps": {
"created": "2026-08-05T12:05:00.000Z",
"accepted": "2026-08-05T14:12:00.000Z",
"declined": null,
"completed": null,
"updated": "2026-08-05T14:12:00.000Z"
}
}
},
"meta": {
"timestamp": "2026-08-05T14:12:00.000Z",
"version": "1.0"
}
}/api/external/v1/orders/:id/declineDecline an incoming order. Requires declineReason. declineMessage is required only when declineReason is OTHER.
{
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}{
"declineReason": "OTHER",
"declineMessage": "We are closing early today"
}curl -X POST "https://www.getbloomdirect.com/api/external/v1/orders/68935f106a9e3d72b872a101/decline" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"declineReason": "OTHER",
"declineMessage": "We are closing early today"
}'{
"success": true,
"data": {
"order": {
"id": "68935f106a9e3d72b872a101",
"orderNumber": "1001",
"status": "DECLINED",
"decline": {
"reason": "OTHER",
"message": "We are closing early today"
},
"recipient": {
"fullName": "Jane Doe",
"address": "123 Main St",
"apt": "Apt 4B",
"city": "Buffalo",
"state": "NY",
"zip": "14201",
"phone": "555-123-4567",
"email": "jane@example.com",
"company": "Acme Corp",
"message": "Happy Birthday!"
},
"customer": {
"fullName": "John Smith",
"email": "john@example.com",
"phone": "555-987-6543"
},
"products": [
{
"name": "Red Roses",
"description": "Dozen premium roses",
"photo": "https://cdn.getbloomdirect.com/products/roses.jpg",
"qty": 1,
"taxable": true,
"price": 59.99
}
],
"totals": {
"currency": "USD",
"productsSubtotal": 59.99,
"deliveryFee": 10,
"originatingFee": 0,
"tax": 4.8,
"orderTotal": 74.79,
"fulfillmentAmount": 69.99
},
"delivery": {
"date": "2026-08-08T00:00:00.000Z",
"window": {
"type": "specific",
"from": "09:00",
"to": "13:00"
},
"instructions": "Leave at front desk"
},
"paidAt": null,
"timestamps": {
"created": "2026-08-05T12:05:00.000Z",
"accepted": null,
"declined": "2026-08-05T14:15:00.000Z",
"completed": null,
"updated": "2026-08-05T14:15:00.000Z"
}
}
},
"meta": {
"timestamp": "2026-08-05T14:15:00.000Z",
"version": "1.0"
}
}/api/external/v1/orders/:id/completeMark an accepted order as completed after fulfillment. Orders in ACCEPTED status can be completed.
{
"x-api-key": "YOUR_API_KEY"
}curl -X POST "https://www.getbloomdirect.com/api/external/v1/orders/68935f106a9e3d72b872a101/complete" \
-H "x-api-key: YOUR_API_KEY"{
"success": true,
"data": {
"order": {
"id": "68935f106a9e3d72b872a101",
"orderNumber": "1001",
"status": "COMPLETED",
"decline": {
"reason": "",
"message": ""
},
"recipient": {
"fullName": "Jane Doe",
"address": "123 Main St",
"apt": "Apt 4B",
"city": "Buffalo",
"state": "NY",
"zip": "14201",
"phone": "555-123-4567",
"email": "jane@example.com",
"company": "Acme Corp",
"message": "Happy Birthday!"
},
"customer": {
"fullName": "John Smith",
"email": "john@example.com",
"phone": "555-987-6543"
},
"products": [
{
"name": "Red Roses",
"description": "Dozen premium roses",
"photo": "https://cdn.getbloomdirect.com/products/roses.jpg",
"qty": 1,
"taxable": true,
"price": 59.99
}
],
"totals": {
"currency": "USD",
"productsSubtotal": 59.99,
"deliveryFee": 10,
"originatingFee": 0,
"tax": 4.8,
"orderTotal": 74.79,
"fulfillmentAmount": 69.99
},
"delivery": {
"date": "2026-08-08T00:00:00.000Z",
"window": {
"type": "specific",
"from": "09:00",
"to": "13:00"
},
"instructions": "Leave at front desk"
},
"paidAt": null,
"timestamps": {
"created": "2026-08-05T12:05:00.000Z",
"accepted": "2026-08-05T14:12:00.000Z",
"declined": null,
"completed": "2026-08-08T15:00:00.000Z",
"updated": "2026-08-08T15:00:00.000Z"
}
}
},
"meta": {
"timestamp": "2026-08-08T15:00:00.000Z",
"version": "1.0"
}
}All API errors use the same response envelope. The HTTP status indicates the category of failure, while error.code provides a stable machine-readable value for your integration.
| HTTP | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | The request contains invalid input or malformed data. |
| 400 | MISSING_DECLINE_REASON | A decline request did not include a decline reason. |
| 400 | MISSING_DECLINE_MESSAGE | The decline reason is "OTHER" but no explanatory message was supplied. |
| 400 | INVALID_DECLINE_REASON | The supplied decline reason is not supported. |
| 400 | DECLINE_MESSAGE_TOO_LONG | The decline message exceeds the allowed length. |
| 401 | MISSING_API_KEY | No API key was supplied with the request. |
| 401 | INVALID_API_KEY | The supplied API key is invalid, disabled, or no longer active. |
| 403 | PRO_REQUIRED | The shop does not currently have an active Bloom Pro subscription. |
| 403 | ACCOUNT_SUSPENDED | The GetBloomDirect shop account is suspended. |
| 403 | ACCOUNT_ARCHIVED | The GetBloomDirect shop account is no longer active. |
| 403 | ACCOUNT_RESTRICTED | The shop account is restricted from API access. |
| 403 | SHOP_NOT_READY_TO_ACCEPT | The fulfilling shop does not currently meet the requirements to accept orders. |
| 403 | FORBIDDEN | The authenticated shop is not permitted to perform the requested action. |
| 404 | ORDER_NOT_FOUND | The requested order does not exist or is not assigned to the authenticated fulfilling shop. |
| 409 | INVALID_TRANSITION | The request conflicts with the order's current lifecycle status. |
| 429 | RATE_LIMIT_EXCEEDED | Too many API requests were made in a short period of time. |
| 500 | SERVER_ERROR | GetBloomDirect encountered an unexpected server-side error. |
Error response format
{
"success": false,
"error": {
"code": "INVALID_TRANSITION",
"message": "Illegal order transition: DECLINED → ACCEPTED"
},
"meta": {
"timestamp": "2026-08-07T12:00:00.000Z",
"version": "1.0"
}
}GetBloomDirect can send order events to your POS webhook endpoint. Webhooks are intended for real-time updates, while the Orders API can be used for recovery polling.
Supported events
order.created — A new fulfillment order has been assigned to the shop.order.accepted — The fulfilling shop accepted the order.order.declined — The fulfilling shop declined the order.order.completed — The fulfilling shop marked the order delivered and completed.Request headers
X-Webhook-Signature: HMAC SHA-256 signature of the raw request body.X-Webhook-Event: The event name.X-Webhook-Delivery-Id: Unique identifier for this delivery.Acknowledgment and duplicate protection
Return an HTTP 2xx response only after the event has been safely stored or processed.
Store each X-Webhook-Delivery-Id. If the same delivery ID is received again, do not process it twice. Return another 2xx response so GetBloomDirect stops retrying it.
Signature verification
Calculate an HMAC SHA-256 digest using your webhook secret and the raw request body. Compare the hexadecimal digest with X-Webhook-Signature.
const expectedSignature = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(rawRequestBody)
.digest("hex");Retry policy
Failed deliveries are retried after approximately 1 minute, 5 minutes, 15 minutes, 1 hour, and 6 hours, for a maximum of six total delivery attempts including the initial attempt.
Missed webhook recovery
Webhooks are a real-time notification mechanism, not the authoritative source of order state. If your integration misses a webhook or is offline, recover changes by polling the Orders endpoint with the since query parameter.
GET /api/external/v1/orders?since=2026-08-05T12:00:00.000Z
Always treat the latest order returned by the Orders API as the current GetBloomDirect state.
Delivery order
Do not assume webhook deliveries will always arrive in lifecycle order. Network delays and retries can cause an older delivery to arrive after a newer one. Use the order's timestamps.updated value and periodically reconcile with the Orders API.
{
"event": "order.completed",
"data": {
"order": {
"id": "68935f106a9e3d72b872a101",
"orderNumber": "1001",
"status": "COMPLETED",
"decline": {
"reason": "",
"message": ""
},
"recipient": {
"fullName": "Jane Doe",
"address": "123 Main St",
"apt": "Apt 4B",
"city": "Buffalo",
"state": "NY",
"zip": "14201",
"phone": "555-123-4567",
"email": "jane@example.com",
"company": "Acme Corp",
"message": "Happy Birthday!"
},
"customer": {
"fullName": "John Smith",
"email": "john@example.com",
"phone": "555-987-6543"
},
"products": [
{
"name": "Red Roses",
"description": "Dozen premium roses",
"photo": "https://cdn.getbloomdirect.com/products/roses.jpg",
"qty": 1,
"taxable": true,
"price": 59.99
}
],
"totals": {
"currency": "USD",
"productsSubtotal": 59.99,
"deliveryFee": 10,
"originatingFee": 0,
"tax": 4.8,
"orderTotal": 74.79,
"fulfillmentAmount": 69.99
},
"delivery": {
"date": "2026-08-08T00:00:00.000Z",
"window": {
"type": "specific",
"from": "09:00",
"to": "13:00"
},
"instructions": "Leave at front desk"
},
"paidAt": null,
"timestamps": {
"created": "2026-08-05T12:05:00.000Z",
"accepted": "2026-08-05T14:12:00.000Z",
"declined": null,
"completed": "2026-08-08T15:00:00.000Z",
"updated": "2026-08-08T15:00:00.000Z"
}
},
"actorShopId": "68935ee86a9e3d72b8729f11"
},
"meta": {
"timestamp": "2026-08-08T15:00:00.000Z",
"version": "1.0",
"deliveryId": "550e8400-e29b-41d4-a716-446655440000"
}
}