Skip to content
Last updated

Soft Deletes

MVMNT uses soft deletes for all resources. When you delete an entity, it's marked with a deletedAt timestamp rather than being permanently removed from the database.

What Are Soft Deletes?

A soft delete marks a record as deleted without actually removing it from the database. The record remains queryable but is filtered out from list endpoints by default.

The deletedAt Field

Every entity in the MVMNT API includes a deletedAt field:

FieldTypeDescription
deletedAtISO 8601 datetime | nullTimestamp when entity was soft-deleted, or null if active

Active Entity

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "friendlyId": "ORD-12345",
  "key": "ERP-ORDER-789",
  "status": "delivered",
  "deletedAt": null,
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-20T14:00:00Z"
}

Soft-Deleted Entity

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "friendlyId": "ORD-12345",
  "key": "ERP-ORDER-789",
  "status": "delivered",
  "deletedAt": "2025-01-20T15:30:00Z",
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-20T15:30:00Z"
}

How Soft Deletes Work

Deleting an Entity

Use the standard DELETE request:

curl -X DELETE https://api.mvmnt.io/v1/orders/ORD-12345 \
  -H "Authorization: Bearer $TOKEN"

Response: 200 OK

What happens:

  1. deletedAt is set to the current timestamp
  2. updatedAt is also updated to the current timestamp
  3. Entity remains in database
  4. Entity is filtered out from list queries by default

List Queries (Filtering Behavior)

Default behavior - soft-deleted entities are excluded:

curl https://api.mvmnt.io/v1/orders \
  -H "Authorization: Bearer $TOKEN"

Response:

{
  "data": [
    {
      "id": "...",
      "friendlyId": "ORD-12346",
      "deletedAt": null
    },
    {
      "id": "...",
      "friendlyId": "ORD-12347",
      "deletedAt": null
    }
  ]
}

ORD-12345 (deleted) is NOT included.

Include deleted entities - use ?includeDeleted=true:

curl "https://api.mvmnt.io/v1/orders?includeDeleted=true" \
  -H "Authorization: Bearer $TOKEN"

Response:

{
  "data": [
    {
      "id": "...",
      "friendlyId": "ORD-12345",
      "deletedAt": "2025-01-20T15:30:00Z"
    },
    {
      "id": "...",
      "friendlyId": "ORD-12346",
      "deletedAt": null
    },
    {
      "id": "...",
      "friendlyId": "ORD-12347",
      "deletedAt": null
    }
  ]
}

Get by ID (Still Accessible)

Soft-deleted entities are still accessible via GET by ID:

curl https://api.mvmnt.io/v1/orders/ORD-12345 \
  -H "Authorization: Bearer $TOKEN"

Response: 200 OK

{
  "id": "550e8400-...",
  "friendlyId": "ORD-12345",
  "deletedAt": "2025-01-20T15:30:00Z",
  ...
}

Your code must check deletedAt to determine if entity is deleted.

Query by Client Key

Deleted entities are also filtered out by default when querying by key:

curl "https://api.mvmnt.io/v1/orders?key=ERP-ORDER-789" \
  -H "Authorization: Bearer $TOKEN"

If the entity is deleted, this returns empty results unless you add ?includeDeleted=true.

Webhooks and Soft Deletes

DELETE Event

When an entity is deleted, a webhook event is triggered:

{
  "event": "order.deleted",
  "timestamp": "2025-01-20T15:30:00Z",
  "data": {
    "id": "550e8400-...",
    "friendlyId": "ORD-12345",
    "key": "ERP-ORDER-789",
    "deletedAt": "2025-01-20T15:30:00Z",
    "status": "delivered"
  }
}

Note: The data object includes deletedAt - your webhook handler must handle this field.

Other Events May Include Deleted Entities

Some webhook events may reference deleted entities (e.g., if a shipment references a deleted carrier). Always check deletedAt on related entities.

Why Soft Deletes?

✅ Benefits

  1. Data Recovery: Entities can be restored if deleted by mistake
  2. Audit Trail: Historical data remains accessible for reporting
  3. Referential Integrity: Related entities don't break when referenced entity is deleted
  4. Compliance: Some industries require retention of deleted records
  5. Undo Operations: Users can recover accidentally deleted data

⚠️ Considerations

  1. Check deletedAt: Your code must handle entities where deletedAt is not null
  2. Webhook Handling: Deleted entities appear in webhook payloads
  3. Storage: Deleted entities still consume database space
  4. Queries: Must use ?includeDeleted=true to see deleted entities in lists

Common Scenarios

Scenario 1: User Deletes Shipment by Mistake

Problem: User accidentally deletes a shipment from the MVMNT UI

Solution:

  1. Shipment is soft-deleted (deletedAt set)
  2. Update the shipment and set deletedAt: null via the API
  3. Shipment is active again

Scenario 2: Referenced Entity Is Deleted

Problem: Shipment references a carrier that was deleted

Example:

{
  "id": "shipment-123",
  "carrierId": "carrier-456",
  "carrier": {
    "id": "carrier-456",
    "name": "ABC Trucking",
    "deletedAt": "2025-01-20T15:30:00Z"
  }
}

Solution: Check deletedAt on nested entities in responses. Deleted entities are only filtered out from list queries by default. They are still present within non-deleted parent entities.

Best Practices

✅ Do

  • Always check deletedAt when processing entities from GET requests
  • Handle deletedAt in webhooks - deleted entities can appear in webhook payloads
  • Implement soft deletes in your system to match MVMNT's behavior
  • Log deletion events for audit trails

❌ Don't

  • Don't assume entities in webhooks are active - always check deletedAt
  • Don't rely on 404 errors for deleted entities - GET by ID still returns 200
  • Don't expect immediate permanent deletion - soft deletes are not reversible via API (yet)
  • Don't forget to update your system when receiving *.deleted webhook events

API Reference

All entities include:

FieldTypeDescription
deletedAtISO 8601 datetime | nullTimestamp when deleted, or null if active

Webhook Events

Deletion events:

  • SHIPMENT_DELETED
  • CUSTOMER_DELETED
  • CUSTOMER_CONTACT_DELETED
  • ...

All deletion event payloads include a non-null deletedAt timestamp.

Next Steps