Skip to main content
Ship one card or a batch of up to 200 cards in a single shipment. Reap handles production, courier handoff, and delivery tracking. You drive the flow with a draft-first API: build the shipment, review it, then submit when ready.

Lifecycle

A shipment moves through production at the factory, courier handoff, and delivery. DELIVERY_FAILED, EXCEPTION, and CANCELED can also occur from most non-terminal states. DELIVERY_FAILED and EXCEPTION are recoverable - the courier may re-attempt and the shipment can move forward.

Shipment statuses

Only DELIVERED and CANCELED are terminal. Some carriers skip intermediate states (for example, OUT_FOR_DELIVERY), so do not assume every status is visited.

Per-card production status

Each card in the shipment carries its own productionStatus. This lets you tell which cards in a multi-card shipment are still being produced versus already complete.

Single card vs multi-card shipments

One endpoint covers both. A shipment with one card and a shipment with up to 200 cards use the same draft-first flow. Use multi-card shipments when you are dispatching cards in bulk to a single hub (a corporate office, a regional distribution point). Use single-card shipments when each card goes directly to the cardholder.

Issue a shipment

1

Create a draft

Call Create a card shipment with the destination address, recipient details, courier choice, and one or more cards. The shipment is created with status: DRAFT.Each card entry includes the cardId, cardDesignId, and a per-card shippingAddress. The per-card address is the final destination printed on the card mailer; it can differ from the box-level destination on multi-card shipments.The cardDesignId on a shipment entry is the design the plastic is produced from, and it can differ from the cardDesignId the card was issued with. The design must be physical-capable and assigned to your project.
2

Adjust the draft (optional)

Use Update shipment, Add a card, and Remove a card to edit a DRAFT shipment. Once submitted, the shipment is frozen.Updating the destination also updates each card whose shipping address still matches the previous destination. A card with a different shipping address keeps its own address.
3

Submit to the manufacturer

Call Submit shipment. The shipment transitions to PLACED and the manufacturer starts production.For multi-card shipments, a cutoffDate is returned. Cards submitted after this cutoff roll into the next production batch. Plan submission with this in mind.On partial failure (some cards accepted, others rejected), the response returns HTTP 207 Multi-Status. The shipment still moves to PLACED with the surviving cards. Rejected cards appear in cards[] with productionStatus: BULK_SHIP_REJECTED and a rejectedAt timestamp.
4

Track production and delivery

Subscribe to CARD_SHIPMENT_STATUS_UPDATED for shipment-level status changes. The webhook fires on every transition (PLACED → IN_PRODUCTION, IN_TRANSIT, etc.). The payload matches Get shipment, including cards[] with each card’s id and production status.

Tracking and webhooks

CARD_SHIPMENT_STATUS_UPDATED is the source of truth for shipment status. Do not poll. The payload includes the same cards[] array as Get shipment, so you can map the shipment to its cards without a follow-up request. When a status change includes courier tracking, trackingNumber and trackingUrl are populated on that payload. Pass the URL through to the cardholder so they can follow the delivery with the courier directly. If you need the latest state on demand (e.g. a customer service agent looking up a specific shipment), call Get shipment.

Testing in sandbox

In sandbox there is no factory or courier, so submitted shipments stay at PLACED until you drive them. Use Simulate shipment status:
Walk the shipment through the same statuses you see in production (IN_PRODUCTION, READY_TO_SHIP, IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERED, and the recoverable / cancel paths). Each call returns 204; observe the change via CARD_SHIPMENT_STATUS_UPDATED.

Couriers and destinations

Set the courier on the draft: Only DHL, FEDEX, and POSTAL can be selected on create or update. After the shipment is placed, the courier on GET responses and shipping webhooks reflects the manufacturer’s assignment and may be SFEXPRESS for some manufacturer and destination combinations (for example cards shipped to Hong Kong), even if you requested DHL or FEDEX. Some countries do not support physical card shipping or require additional fields. The API will reject a draft with a clear error if:
  • The destination country is not supported (SHIPPING_NOT_ALLOWED_FOR_COUNTRY)
  • A zone (state or province) is required for the destination (ZONE_REQUIRED) or the supplied zone is invalid (INVALID_ZONE)
  • The chosen courier does not deliver to the destination (COURIER_NOT_SUPPORTED)
  • The recipient phone number is invalid or its dial code does not match the destination country (SHIPPING_PHONE_INVALID, SHIPPING_PHONE_DIAL_CODE_MISMATCH)
Validate addresses up front in your UI when possible. The same checks are run on draft creation and on submission, so a draft that creates successfully will still pass these checks at submit time unless you change the address.

What’s next

Once a physical card is delivered, the cardholder activates it with the 6-digit code on the mailer. See Activation for the activation flow and lost-code recovery.