Gifting API
Send branded merchandise programmatically. Integrate gifting into your CRM, sales workflows, or any application with a simple REST API.
Quick Start
Three steps to send your first gift programmatically.
Get your API key
Go to Dashboard → Integrations and create an API key. Requires a Merch OS subscription.
Stock your storefront
Add products to a storefront. The API sends from stocked inventory in your warehouse.
Create a send
POST to /api/v1/sends with recipient address and items. We handle fulfillment and shipping.
Authentication
All API requests require a valid API key passed in the X-API-Key header. Keys are scoped to your company and require a Merch OS subscription.
curl https://api.brandmerch.com/api/v1/sends/inventory?storefrontId=sf_abc123 \
-H "X-API-Key: bm_live_your_key_here"SHA-256 hashed
Keys are stored as irreversible hashes
Company-scoped
Each key is tied to one company account
Revocable instantly
Revoke any key from the dashboard immediately
Base URL
https://api.brandmerch.comAPI Endpoints
Click any endpoint to expand the full documentation.
Error Codes
All errors return a JSON body with an error field describing the issue.
| Code | Meaning | Common Cause |
|---|---|---|
| 400 | Bad Request | Missing required fields or invalid data |
| 401 | Unauthorized | Missing, invalid, or revoked API key |
| 403 | Forbidden | No Merch OS subscription or account deactivated |
| 404 | Not Found | Storefront or send ID not found / not owned |
| 409 | Conflict | Insufficient inventory for requested quantities |
| 500 | Internal Error | Server error — retry or contact support |
Webhooks
Subscribe to real-time event notifications. Webhooks are signed with HMAC-SHA256 for verification and retried up to 3 times with exponential backoff.
Available Events
send.createdA new send has been created and inventory reserved
send.shippedA send has shipped with tracking information
send.deliveredA send has been confirmed delivered
Payload Format
{
"event": "send.shipped",
"sendId": "send_1700000000000_a1b2c3d",
"data": {
"trackingNumber": "1Z999AA10123456784",
"carrier": "UPS",
"shippedAt": "2025-03-25T14:30:00.000Z"
},
"timestamp": "2025-03-25T14:30:05.000Z"
}Headers
| Header | Description |
|---|---|
| X-BrandMerch-Signature | HMAC-SHA256 hex digest of the request body |
| X-BrandMerch-Event | The event type (e.g. send.shipped) |
| Content-Type | application/json |
Verifying Signatures (Node.js)
import crypto from 'crypto';
function verifySignature(body: string, signature: string, secret: string): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post('/webhooks/brandmerch', (req, res) => {
const signature = req.headers['x-brandmerch-signature'];
const isValid = verifySignature(
JSON.stringify(req.body),
signature,
process.env.BRANDMERCH_WEBHOOK_SECRET
);
if (!isValid) return res.status(401).send('Invalid signature');
const { event, sendId, data } = req.body;
// Handle the event...
res.status(200).send('OK');
});Idempotency
Pass an idempotencyKey in the request body to prevent duplicate sends. If a send with the same key already exists for your company, the API returns the existing send instead of creating a new one (with idempotent: true in the response).
// First request → creates the send
{ "storefrontId": "sf_abc", "idempotencyKey": "onboard-jane-2025", ... }
// → 201 { "sendId": "send_...", "status": "reserved" }
// Retry with same key → returns existing send
{ "storefrontId": "sf_abc", "idempotencyKey": "onboard-jane-2025", ... }
// → 200 { "sendId": "send_...", "status": "reserved", "idempotent": true }Developer FAQ
Common technical questions about the Gifting API.
How do I verify webhook signatures?
Each webhook delivery includes an X-BrandMerch-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with the secret returned when you created the webhook subscription. Recompute the HMAC on your end and compare to verify authenticity.
What are the rate limits?
The Sends API shares the global rate limit of 1,000 requests per 15 minutes per API key. Inventory checks (GET) and send creation (POST) both count toward this limit. If you hit the limit, the API returns 429 with a Retry-After header.
What happens if a send fails due to insufficient stock?
The API returns a 409 Conflict with a stockIssues array showing each item's requested vs. available quantity. No order is created and no inventory is reserved. You can retry after restocking.
Can I send to multiple recipients in one API call?
Each POST /sends creates a single shipment to one recipient. For bulk sends, make one API call per recipient. Use idempotency keys to safely retry without creating duplicates.
How do I handle API errors in my integration?
The API returns structured JSON errors with an error field on every non-2xx response. 400 errors indicate invalid input, 401/403 indicate auth issues, 404 means the resource was not found, and 409 means a stock conflict. Always check the HTTP status code and error message before retrying.
Can I test the API without creating real shipments?
Use a storefront in DRAFT status for testing. Sends created against draft storefronts will create real fulfillment requests in your warehouse dashboard, but you can cancel them before shipping. We recommend using a dedicated test storefront with a small amount of test inventory.
How long do API keys last?
API keys do not expire. They remain active until you explicitly revoke them from the Integrations page in your Team Dashboard. We recommend rotating keys periodically and revoking any that are no longer in use.
Ready to integrate?
Get started with the Gifting API today. Create your first API key and send a test gift in minutes.