Errors, retries and limits

The conventions every endpoint shares, so one error handler and one retry policy cover the whole API.

Status. The SignWren API is opening in stages and may not be on your account yet. If Settings shows an API keys section, you can make sandbox keys now; live keys come with the Pro and Business plans. SignWren is an electronic signature app for small businesses; it is not a law firm and does not give legal advice.

What does an error look like?

Every error has the same JSON body, with a stable code to branch on and a message written to be shown to a person.

{
  "error": {
    "code": "WARNING_UNACKNOWLEDGED",
    "message": "This document looks like one that electronic signature laws exclude.",
    "param": "acknowledge_warnings",
    "request_id": "req_5f2b8c1d9e0a4b3c7d6e5f40",
    "doc_url": null,
    "details": { "categories": ["EXC_WILL"] }
  }
}

param names the request property the error is about, when there is one, and details adds facts for some codes, such as the missing business details for SEND_BLOCKED. Messages never contain stack traces, SQL, file paths or another account's data. Every answer, error or not, carries a Request-Id header with the same id; quote it if you contact us.

StatusCodesMeaning
400BAD_REQUESTThe request can’t be read: the body isn’t a JSON object, the upload is unreadable, or the Idempotency-Key header is malformed.
401UNAUTHENTICATEDNo key, or an unknown, revoked or expired one.
402PLAN_REQUIRED, USAGE_LIMIT_REACHED, PLAN_LIMIT_REACHEDThe plan does not include this, or a limit was reached.
403SCOPE_REQUIRED, FORBIDDEN, ROLE_FORBIDDENThe key lacks a scope, or its member’s role can’t do this.
404NOT_FOUNDNot found, or in another organization or environment.
409INVALID_STATE, ENVELOPE_LOCKED, IDEMPOTENCY_IN_PROGRESSThe envelope’s state refuses it, or the same idempotency key is still running.
413, 415TOO_LARGE, UNSUPPORTED_MEDIA_TYPE, FILE_TOO_LARGE, UNSUPPORTED_TYPEThe upload is too big or not a file type the API takes.
422VALIDATION, SEND_BLOCKED, WARNING_UNACKNOWLEDGED, IDEMPOTENCY_MISMATCH, ...A value is missing or out of range (param names it), or the request is refused as it stands; details says what is missing.
429RATE_LIMITEDToo many requests. Wait for Retry-After.
5xxINTERNAL, API_NOT_CONFIGUREDSomething went wrong on SignWren’s side. Safe to retry with the same idempotency key.

New codes can be added without a new API version, so treat an unknown code by its HTTP status.

How do idempotency keys work?

Send an Idempotency-Key header with any POST, and if the same key arrives again from the same API key within 24 hours, SignWren replays the first answer instead of doing the work twice. Use a UUID, or a key built from your own record so a restarted job reuses it.

curl "$SIGNWREN_API/envelopes" \
  -H "Authorization: Bearer $SIGNWREN_API_KEY" \
  -H "Idempotency-Key: crm-deal-1042-lease" \
  -H "Content-Type: application/json" \
  -d @envelope.json
  • A replayed answer has the header Idempotent-Replayed: true.
  • The same key with a different request is 422 IDEMPOTENCY_MISMATCH.
  • The same key while the first request is still running is 409 IDEMPOTENCY_IN_PROGRESS; try again shortly.
  • Keys are 1 to 255 printable ASCII characters.

Sending is protected twice: even without a key, a second send of the same envelope is refused by its state with 409 INVALID_STATE.

When should my code retry?

Retry on 429, on 500, 502, 503 and 504, and on network errors, with the same idempotency key and a growing wait between tries. Don't retry other 4xx answers; they will fail the same way. The Node SDK does all of this for you: two retries by default, half a second then a second apart with some jitter, and it waits for Retry-After when the API sends one.

What are the rate limits?

The proposed limits are 25 requests a second for each live key and 10 for each sandbox key, with a short burst allowed and a ceiling for each organization. Every answer carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset, and a refused request is 429 RATE_LIMITED with a Retry-After header in seconds. Reminders have their own limit of one per recipient every 24 hours.

How does pagination work?

List endpoints take limit (1 to 100, default 25) and starting_after, the id of the last item you already have, and answer newest first with has_more telling you whether to ask again.

curl "$SIGNWREN_API/envelopes?limit=100&status=sent" -H "Authorization: Bearer $SIGNWREN_API_KEY"
# { "object": "list", "data": [ ... ], "has_more": true }

curl "$SIGNWREN_API/envelopes?limit=100&status=sent&starting_after=env_..." -H "Authorization: Bearer $SIGNWREN_API_KEY"

When does the API version change?

New endpoints, new optional fields and new event types are added to /v1 without notice in the version, so ignore fields you don't know. Removing or renaming a field, changing a type or changing a default would need /v2. Every change is listed in the changelog the day it ships, and the build fails if a change to the spec would break /v1 clients.

Last checked against the API spec on .