Paused transfers
Upload documents and resume a transfer that waits for a supporting document, sender details or a limit decision.
Gravv accepts some transfers that cannot go ahead yet. For example, the bank needs an invoice, the payout route needs the sender's date of birth, or the amount is over a limit. Gravv does not refuse these transfers. It returns HTTP 200 with transfer_status paused, lists what it needs in requirements, and waits. You send what it needs with POST /v1/transfer/{id}/resume.
Example. A company sends 4,800.00 USD by SWIFT to a contractor in Abuja without a document. The response is paused, with pause_reason supporting_document_required and expires_at 72 hours later. The company uploads the service contract and resumes the transfer with the document's id. The payout goes ahead, and Gravv does not charge the fee again. If the company had done nothing, the transfer would have failed at expires_at and Gravv would have refunded the fee.
Read the pause
{
"data": {
"amount": "4800",
"amount_currency": "USD",
"reference": "c1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f607",
"date_created": "2026-10-13T10:02:11.000Z",
"transfer_status": "paused",
"transaction_id": "0e1f2a3b-4c5d-4e6f-8a7b-9c0d1e2f3a4b",
"local_amount": null,
"local_currency": null,
"fee": "25",
"fee_currency": "USD",
"requires_approval": false,
"status": "awaiting_supporting_document",
"park_reason": "supporting_document",
"pause_reason": "supporting_document_required",
"requirements": [
{
"type": "supporting_document",
"description": "resume with supporting_document_ids: at least one supporting document for this payout"
}
],
"expires_at": "2026-10-16T10:02:11Z"
},
"error": null
}
| Field | Meaning |
|---|---|
pause_reason |
Why it paused: per_transfer, daily, weekly, monthly, annual, annual_requires_approval (a limit), screening, sender_details_required or supporting_document_required |
requirements[] |
What to send. type is the field or action. levels lists the verification levels Gravv accepts |
breached_window, remaining_usd |
For a limit pause, the window the transfer exceeded and what is left in it, in USD |
expires_at |
When the pause ends, by default 72 hours after the pause. The transfer then fails, and Gravv returns the amount and fee |
Gravv also sends the pause as the webhook transfer.requires_information (event_data.status paused, reason, and limit_details with the requirements). A document pause can also start later, shortly before the payout, if the bank's requirement changed. In that case you get only the webhook. Store reference, because it is the id you resume.
What each requirement asks for
requirements[].type |
Resume with |
|---|---|
supporting_document |
supporting_document_ids, and nothing else |
remitter_full_name, remitter_date_of_birth, remitter_address, remitter_country |
additional_information with those fields |
customer_email |
Nothing in the body. Add an email to the customer with PUT /v1/customers/{customer_id}, then resume with {} |
remitter_verification |
remitter_verification at one of the listed levels (businesses that verify their own senders) |
screening_clear |
remitter_verification whose screening values are all clear |
admin_review |
Nothing you can send. Only Gravv can release it. Contact support with the reference, or let it expire and send within remaining_usd |
Never invent verification details. Send only what you checked.
Upload a supporting document
Some banks ask for a document on SWIFT payouts, such as an invoice or a contract. Upload it with POST /v1/transfer/documents, then pass its id on the transfer (supporting_document_ids) or on the resume:
curl --request POST \
--url https://api.gravv.xyz/v1/transfer/documents \
--header 'Api-Key: <API_KEY>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 4f8b2d6a-9c1e-4a7b-8e3d-5f6a7b8c9da6' \
--data '
{
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"document_type": "contract",
"description": "Consulting contract September 2026",
"file_name": "contract-cz-2026.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQKJcfsj6IKMSAwIG9iago8PC9UeXBlL0NhdGFsb2c+PgplbmRvYmoK"
}
'
{
"data": {
"content_type": "application/pdf",
"created_at": "2026-10-13T10:05:57.665487Z",
"description": "Consulting contract September 2026",
"document_type": "contract",
"file_name": "contract-cz-2026.pdf",
"id": "9f4c2e1a-7b3d-4c5e-8f6a-1b2c3d4e5f60",
"size_bytes": 184233
},
"error": null
}
Rules for documents:
contentis the file as standard base64. The file is a PDF, PNG or JPEG, andcontent_typemust match the file itself.- A file can be at most 700 KB. In sandbox, keep it under 500 KB, because sandbox refuses requests from about 600 KB with a 413 that says 10MB.
document_typeis one ofinvoice,proforma_invoice,purchase_order,contract,receipt,bill_of_lading,customs_declaration,bank_statement,proof_of_income,tax_documentorother.otherneeds adescription(at most 140 characters).- Upload the document for the customer who sends the transfer. Each document can belong to one transfer only, and a transfer takes up to 5 documents. Gravv deletes a document that no transfer uses after 7 days.
Resume the transfer
Send what requirements asked for to POST /v1/transfer/{reference}/resume. Use a new Idempotency-Key on every attempt. The resume body is strict. Unlike the transfer request, it refuses any unknown field.
curl --request POST \
--url https://api.gravv.xyz/v1/transfer/c1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f607/resume \
--header 'Api-Key: <API_KEY>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 7a1c5e9b-2d4f-4b8a-9c6e-0d1e2f3a4bb7' \
--data '
{
"supporting_document_ids": [
"9f4c2e1a-7b3d-4c5e-8f6a-1b2c3d4e5f60"
]
}
'
{
"data": {
"transfer_id": "c1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f607",
"status": "approved_awaiting_execution",
"transfer_status": "pending",
"resumed": true
},
"error": null
}
resumed: truemeans the transfer moves on. Gravv sends atransfer.resumedwebhook, then the usual transfer events.statusnames an internal step, so do not build logic on it.resumed: falsewith newrequirementsmeans something is still missing, or the transfer is still over a cap. Send what is listed, with another new key.
For a sender-details pause, send the missing fields:
curl --request POST \
--url https://api.gravv.xyz/v1/transfer/3019b5b3-1ad0-4f00-809a-8e52f727ba0d/resume \
--header 'Api-Key: <API_KEY>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 1c6e0a4d-8b2f-4e9c-a7d1-2e3f4a5b6cc8' \
--data '
{
"additional_information": {
"remitter_date_of_birth": "1988-04-17",
"remitter_address": {
"address_line1": "27 Ashburnham Road",
"city": "London",
"postal_code": "SW10 0PL",
"country": "GB"
}
}
}
'
To avoid a sender-details pause, send additional_information on the transfer itself. Gravv uses its fields ahead of the customer profile.
What can go wrong
| Response | Why | Fix |
|---|---|---|
400 this transfer is paused for a supporting document: resume it with supporting_document_ids only, without remitter_verification or additional_information |
Extra fields on a document pause | Send only supporting_document_ids |
400 invalid request body: json: unknown field "documents" |
A field the resume does not know | Use the exact field names |
400 this transfer is not paused (with transfer_status) |
Already resumed, failed or completed | Read the transaction |
400 remitter_date_of_birth must be a date as YYYY-MM-DD |
Wrong date format | Send 1988-04-17 |
400 the remitter information does not match the sender this transfer was paused for; resume with the same remitter_id, or initiate a new transfer |
A different remitter_id |
Use the same one, or start a new transfer |
400 supporting_document_ids: each id must be a document uploaded for this customer and not used by another transfer |
Wrong customer, already used, or older than 7 days | Upload it again for the sending customer |
400 content: the file is not a application/pdf |
content_type does not match the file |
Send the real type |
400 content: the file is 812 KB (831488 bytes); the largest accepted is 700 KB (716800 bytes). … |
The file is over 700 KB | Compress it to 700 KB or less |
413 the uploaded file is too large — the maximum is 10MB |
In sandbox, a request from about 600 KB, whatever the message says. In live, a file over about 10 MB | Compress it: under 500 KB in sandbox, 700 KB or less in live |
422 ERROR_CODE_SUPPORTING_DOCUMENT_REQUIRED |
You resumed with an empty list. Or document pauses are switched off and you sent a transfer without a required document | Upload, then resume (or send again) with the id and a new key |
422 transfers are not permitted for this sender (ERROR_CODE_SUBJECT_BLOCKED) |
The sender is blocked | Contact support. Do not retry |
410 ERROR_CODE_TRANSFER_PAUSE_EXPIRED |
Past expires_at. The transfer failed and Gravv refunded it |
Start a new transfer with what was missing |
410 ERROR_CODE_TRANSFER_PAUSE_CANCELLED |
Gravv cancelled the pause | Start a new transfer |
409 the paused transfer changed while this request ran; please retry |
Two resumes at once | Retry once with a new key |
404 transfer workflow not found |
The id is the transaction_id, or another business's transfer |
Use the transfer reference |
400 insufficient balance on resume |
The balance was spent while paused | Fund the account, then resume with a new key |
503 transfer limits are temporarily unavailable, please retry |
Gravv cannot check limits right now | Retry with backoff |
When a pause ends before you resume the transfer, Gravv sends transfer.status.failed with event_data.reason supporting_document_expired, sender_details_expired or limit_pause_expired (or the _cancelled forms).
Testing in sandbox
In sandbox you can test uploads and the resume checks, such as wrong ids, extra fields and the size limit. A real pause depends on the bank's setting for the account, the payout route and your limits policy. You cannot force one with a test value.
Related: Transfer limits, and the recipes SWIFT with a document pause, Stay within transfer limits and Send money to Ghana.