> ## Documentation Index
> Fetch the complete documentation index at: https://docs.grantex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Withdraw Consent

> Withdraw a DPDP consent record. Optionally revokes the underlying grant, and asks the developer to delete processed data.

## Endpoint

```
POST /v1/dpdp/consent-records/:recordId/withdraw
```

## Authentication

Requires a developer API key in the `Authorization` header.

## Request Headers

| Header | Value |
| - | - |
| `Authorization` | `Bearer <api_key>` |
| `Content-Type` | `application/json` |

## Path Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `recordId` | `string` | Yes | The consent record ID to withdraw |

## Request Body

| Field | Type | Required | Description |
| - | - | - | - |
| `reason` | `string` | Yes | Reason for consent withdrawal (up to 1,000 characters) |
| `revokeGrant` | `boolean` | No | If `true`, revokes the underlying grant (and every grant delegated from it when the server sets `DPDP_REVOCATION_CASCADE=true`). Default `false`, or `true` when the server sets `DPDP_WITHDRAWAL_REVOKES_GRANT=true` |
| `deleteProcessedData` | `boolean` | No | If `true`, emits a `dpdp.data_deletion.requested` webhook event asking the developer to delete the data it processed under this consent |

The body must be a JSON object; a missing or malformed body is `400`.

A Data Principal may withdraw consent at any time, and withdrawing is to be
as easy as giving consent (DPDP Act s.6(4)); offering that means is the
fiduciary's user interface, which calls this endpoint. After a withdrawal the
Data Fiduciary, and its processors, must cease processing within a reasonable
time (s.6(6)). These provisions apply from 13 May 2027 (DPDP Rules 2025 r.1).
Revoking the grant stops Grantex-mediated processing under that
grant: it is marked revoked with `revokedAt`, the revocation cache is updated
and a `grant.revoked` event is emitted. By default only the record's own grant
is revoked, as this endpoint always did; grants delegated from it keep
working. A server that sets `DPDP_REVOCATION_CASCADE=true` revokes through the
same cascade as `DELETE /v1/grants/:id` instead (delegated grants,
credentials, wallet reservations). Only an active grant is revoked. A server
operator who wants every
withdrawal to revoke unless the caller says otherwise sets
`DPDP_WITHDRAWAL_REVOKES_GRANT=true`; an explicit `revokeGrant: false` still
wins.

Grantex holds no personal data the fiduciary processed. `deleteProcessedData`
therefore does not delete or rewrite anything in Grantex (the audit log is a
tamper-evident hash chain and is never modified); it asks the developer, by
webhook, to delete the data in its own systems.

The withdrawal, the grant revocation and the audit entry
(`grantex.dpdp.consent_withdrawn`) are one transaction. Only an `active`
record can be withdrawn, so of two concurrent withdrawals exactly one
succeeds.

## Example Request

```bash theme={null}
curl -X POST https://api.grantex.dev/v1/dpdp/consent-records/crec_01HXYZ.../withdraw \
  -H "Authorization: Bearer gx_..." \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "No longer wish to share data for analytics",
    "revokeGrant": true,
    "deleteProcessedData": true
  }'
```

## Response -- 200 OK

```json theme={null}
{
  "recordId": "crec_01HXYZ...",
  "status": "withdrawn",
  "withdrawnAt": "2026-04-05T14:00:00.000Z",
  "grantRevoked": true,
  "dataDeleted": false,
  "dataDeletionRequested": true
}
```

## Response Fields

| Field | Type | Description |
| - | - | - |
| `recordId` | `string` | The consent record ID |
| `status` | `string` | Updated status: `withdrawn` |
| `withdrawnAt` | `string` | ISO-8601 timestamp of withdrawal |
| `grantRevoked` | `boolean` | Whether this withdrawal revoked the grant (`false` if it was not asked to, or the grant was no longer active) |
| `dataDeleted` | `boolean` | Whether Grantex itself deleted data. Always `false`: Grantex holds none of the fiduciary's processed data |
| `dataDeletionRequested` | `boolean` | Whether a `dpdp.data_deletion.requested` event was sent to the developer |

## Error Responses

| Status | Code | Description |
| - | - | - |
| 400 | `BAD_REQUEST` | Missing or non-object body, missing `reason`, or a non-boolean flag |
| 401 | `UNAUTHORIZED` | Invalid or missing API key |
| 404 | `NOT_FOUND` | Consent record not found |
| 409 | `ALREADY_WITHDRAWN` | Consent has already been withdrawn |
| 409 | `CONSENT_ERASED` | The record was erased |
| 409 | `CONSENT_EXPIRED` | The record has expired |

## SDK Examples

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { Grantex } from '@grantex/sdk';

  const grantex = new Grantex({ apiKey: 'gx_...' });

  const result = await grantex.dpdp.withdrawConsent('crec_01HXYZ...', {
    reason: 'No longer wish to share data',
    revokeGrant: true,
    deleteProcessedData: true,
  });
  ```

  ```python Python theme={null}
  from grantex import Grantex

  grantex = Grantex(api_key="gx_...")

  result = grantex.dpdp.withdraw_consent(
      "crec_01HXYZ...",
      reason="No longer wish to share data",
      revoke_grant=True,
      delete_processed_data=True,
  )
  ```
</CodeGroup>

## Ownership

Grantex is owned by Orchestrum Technologies LLP. Inventor and owner: Sanjeev Kumar. Ownership contact: [sanjeev@orchestrum.in](mailto:sanjeev@orchestrum.in) or [mishra.sanjeev@gmail.com](mailto:mishra.sanjeev@gmail.com).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.