Lifecycle
Send, read, list, edit, and cancel a parcel after it's created.
Send
/parcels/:id/sendSubmits a created parcel to its carrier. 409 if the parcel isn't
created (already sent, cancelled, etc.). A 502 carrier_error leaves
status at created. A timeout can still leave the carrier outcome uncertain; check tracking and carrier state before resubmitting. It does not get stuck
half-submitted.
curl -X POST "https://apis.cloud.feeef.org/v1/parcels/pcl_8Xw…/send" \
-H "Authorization: Bearer $FEEEF_CLOUD_KEY"Validate (NOEST)
/parcels/:id/validateLocks a carrier parcel after create when the adapter exposes
capabilities.validate (NOEST today). Returns 501 carrier_unsupported
otherwise. Already-validated parcels succeed as a no-op. On send, NOEST
accounts auto-validate unless config.autoValidate is set to false.
curl -X POST "https://apis.cloud.feeef.org/v1/parcels/pcl_8Xw…/validate" \
-H "Authorization: Bearer $FEEEF_CLOUD_KEY"Read
/parcels/:idIncludes the full events[] timeline in the same response — usually enough
that you don't need a separate call to
/parcels/:id/events unless you specifically need
pagination over a long history.
curl "https://apis.cloud.feeef.org/v1/parcels/pcl_8Xw…" \
-H "Authorization: Bearer $FEEEF_CLOUD_KEY"List
/parcels?status=&carrier=&stateCode=&createdAfter=&q=&limit=&cursor=Cursor-paginated — see Conventions. Both SDKs ship a pagination helper that walks every page for you:
import { CloudClient, iteratePages } from '@cloud/sdk'
const client = new CloudClient({ apiKey: process.env.FEEEF_API_KEY! })
for await (const parcel of iteratePages((cursor) =>
client.parcels.list({ status: 'in_transit', cursor }),
)) {
console.log(parcel.trackingId)
}Edit
/parcels/:idFree-form while the parcel is still created. After submission, edits are
capability-checked per carrier — an unsupported field comes back as 501 carrier_unsupported, naming the field in error.details. Check
/geo/couriers if you need to know ahead of time
whether a carrier account supports post-submission edits at all.
curl -X PATCH "https://apis.cloud.feeef.org/v1/parcels/pcl_8Xw…" \
-H "Authorization: Bearer $FEEEF_CLOUD_KEY" \
-H "Content-Type: application/json" \
-d '{ "recipient": { "phone": "0551222333" } }'Remarks, return & redelivery (NOEST)
/parcels/:id/remarksAdds a carrier-side update note (add/maj). Body: { "content": "…" } (max 255).
/parcels/:id/request-returnAsks NOEST to return the parcel to the partner (ask/return).
/parcels/:id/request-redeliveryAsks NOEST for another delivery attempt (ask/new-tentative).
All three require a submitted parcel with a tracking id and a carrier that
declares the matching capability — otherwise 501 carrier_unsupported.
Cancel
/parcels/:id/cancelCancels at the carrier where supported. { "force": "local" } detaches the
parcel locally when the carrier has no cancel operation at all — the
platform record moves to cancelled even though nothing was told to the
carrier, which is the honest outcome when there's genuinely no API for it.
curl -X POST "https://apis.cloud.feeef.org/v1/parcels/pcl_8Xw…/cancel" \
-H "Authorization: Bearer $FEEEF_CLOUD_KEY" \
-H "Content-Type: application/json" \
-d '{ "force": "local" }'