GewapeSignGewapeSign

GewapeSign API reference

Sovereign e-signature and contract lifecycle for recurring services.

GewapeSign keeps documents, signer details and audit records in the customer's chosen Gewape region (Rwanda first). Two halves:

  • Documents - send any PDF for signature, follow it, download the signed copy and its certificate.
  • Lifecycle - your billing system tells GewapeSign what was paid and what renews; GewapeSign sends the right contract at the right time and, on an explicit decline, proposes the billing actions (void the renewal invoice, end the service at term end) for your approval. Nothing destructive runs without your approval and audit.

Conventions

  • Auth: Authorization: Bearer <key>. Keys are per organisation, created by an owner or admin in the console (Developers): gsk_test_... (test mode: documents are created but no email is ever sent) and gsk_live_.... OAuth 2.0 for add-ins is planned.
  • Every POST accepts Idempotency-Key (any unique string, kept 24 h). Repeating a request with the same key returns the first result and never creates a second document.
  • Errors are application/problem+json (RFC 9457). Rate limits with RateLimit-* headers are planned.
  • Timestamps are RFC 3339 UTC. IDs are opaque strings with a type prefix (doc_, ctr_, whk_, cmd_).
  • Webhooks are signed: GewapeSign-Signature: t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<raw body>"> with your endpoint secret; reject if the signature does not match or t is older than 5 minutes. Each delivery also carries GewapeSign-Event and GewapeSign-Delivery (the event id: use it to ignore repeats). Any non-2xx answer is retried with exponential backoff (30 s, doubling, up to 6 h between attempts); after 10 attempts the delivery is marked dead and can be redelivered from the delivery log.

Base URL

https://api.gewapesign.com/api/v1

Create keys in the GewapeSign console under Developers. Use a gsk_test_ key while you build: test documents are real but no email is sent.

Documents

Send a PDF for signature and follow it.

GET/documents

List documents

Parameters

statusquery · DocumentStatus
external_refquery · string

Your own reference, exact match

cursorquery · string
limitquery · integer

Responses

  • 200 OK · object
curl -X GET https://api.gewapesign.com/api/v1/documents \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
POST/documents

Create a document (and optionally send it)

Upload a PDF (multipart: file + a JSON payload) and place each field by position: x/y are the field's top-left corner and width/height its size, all as a percentage of the page. At least one field is required. Creating from a template and text tags written in the document (e.g. {{signature:1}}) are planned.

Parameters

Idempotency-Keyheader · string

Request · multipart/form-data

FieldTypeNotes
file requiredstring (binary)

PDF, max 20 MB

payload requiredDocumentCreate

payload (JSON)

FieldTypeNotes
title requiredstringmaxLength 250
external_refstring

Your reference (invoice, deal, ticket); returned in webhooks

maxLength 200
signers requiredarray of SignerminItems 1, maxItems 20
fields requiredarray of Field

Where each signer signs

minItems 1
sequentialbooleandefault true
messagestringmaxLength 2000
sendboolean

Send immediately after creation

default false
expires_in_daysintegerminimum 1, maximum 365
remindersobject

Responses

  • 201 Created · Document
  • 400 Error (RFC 9457) · Problem
  • 409 Error (RFC 9457) · Problem
curl -X POST https://api.gewapesign.com/api/v1/documents \
  -H "Authorization: Bearer $GEWAPESIGN_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F file=@contract.pdf \
  -F 'payload={"title":"Service agreement","signers":[{"name":"A. Uwase","email":"a.uwase@example.com"}],
     "fields":[{"signer":1,"type":"signature","page":1,"x":10,"y":80,"width":30,"height":6}],"send":true}'
POST/documents/detect-fields

Propose signature fields for a PDF (nothing is stored)

Finds signature blocks in the PDF's text (a "Signature" cue and the blank next to it, with the "Name" and "Date" lines of the same block, per column) and matches each block to a signer: by the signer's name, then by the company in their email domain, then by elimination. Blocks the rules cannot settle are matched by our own language model, which runs in Rwanda. The document is never sent outside Gewape. Scanned PDFs without a text layer return no fields and a note. Review the proposal, then pass the fields to POST /documents.

Request · multipart/form-data

FieldTypeNotes
file requiredstring (binary)

PDF, max 20 MB

payload requiredobject

payload (JSON)

FieldTypeNotes
signers requiredarray of SignerminItems 1, maxItems 20

Responses

  • 200 Proposed fields · object
  • 400 Error (RFC 9457) · Problem
  • 422 Error (RFC 9457) · Problem
curl -X POST https://api.gewapesign.com/api/v1/documents/detect-fields \
  -H "Authorization: Bearer $GEWAPESIGN_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
GET/documents/{id}

Get a document and its signers' status

Parameters

id requiredpath · string

Responses

  • 200 OK · Document
  • 404 Error (RFC 9457) · Problem
curl -X GET https://api.gewapesign.com/api/v1/documents/doc_... \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
POST/documents/{id}/send

Send a draft document to its signers

Parameters

id requiredpath · string
Idempotency-Keyheader · string

Responses

  • 200 Sent · Document
  • 409 Error (RFC 9457) · Problem
curl -X POST https://api.gewapesign.com/api/v1/documents/doc_.../send \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
POST/documents/{id}/remind

Remind signers who have not signed yet

Parameters

id requiredpath · string
Idempotency-Keyheader · string

Responses

  • 202 Reminder queued
curl -X POST https://api.gewapesign.com/api/v1/documents/doc_.../remind \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
POST/documents/{id}/void

Withdraw a document that is not yet completed

Parameters

id requiredpath · string
Idempotency-Keyheader · string

Request · application/json

FieldTypeNotes
reason requiredstringmaxLength 500

Responses

  • 200 Voided · Document
  • 409 Error (RFC 9457) · Problem
curl -X POST https://api.gewapesign.com/api/v1/documents/doc_.../void \
  -H "Authorization: Bearer $GEWAPESIGN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Replaced by a new version"}'
GET/documents/{id}/signed.pdf

Download the signed PDF (completed documents only)

Parameters

id requiredpath · string

Responses

  • 200 The signed PDF. `Digest` header carries its SHA-256. · string (binary)
  • 409 Error (RFC 9457) · Problem
curl -X GET https://api.gewapesign.com/api/v1/documents/doc_.../signed.pdf \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
GET/documents/{id}/certificate.pdf

Download the signing certificate (who signed, when, from where, against which document hash)

Parameters

id requiredpath · string

Responses

  • 200 PDF · string (binary)
curl -X GET https://api.gewapesign.com/api/v1/documents/doc_.../certificate.pdf \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
GET/documents/{id}/proof

Independent proof for the document (tamper-evident, independently verifiable)

For each fingerprint (original, and signed once completed): the salted commitment, an RFC 3161 timestamp token from the GewapeSign time-stamping authority, and the Bitcoin anchor via OpenTimestamps (pending until a block confirms it; download the proof again later). Check it without contacting Gewape at https://gewapesign.com/verify/ or with the offline verifier published there. Proves the file existed in exactly this form no later than the stated times; it does not by itself identify the signers.

Parameters

id requiredpath · string

Responses

  • 200 The proof (JSON) · object
  • 404 Error (RFC 9457) · Problem
curl -X GET https://api.gewapesign.com/api/v1/documents/doc_.../proof \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
GET/documents/{id}/proof.zip

The same proof as a zip (proof.json, .tsr tokens, .ots proofs, TSA certificates) for standard tools

Parameters

id requiredpath · string

Responses

  • 200 Zip archive · string (binary)
curl -X GET https://api.gewapesign.com/api/v1/documents/doc_.../proof.zip \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
GET/documents/{id}/audit

The audit trail as data (hash-chained; each entry carries the hash of the previous one)

Parameters

id requiredpath · string

Responses

  • 200 OK · array of AuditEntry
curl -X GET https://api.gewapesign.com/api/v1/documents/doc_.../audit \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"

Webhooks

Get notified when documents and contracts change.

GET/webhooks

List webhook endpoints

Responses

  • 200 OK · object
curl -X GET https://api.gewapesign.com/api/v1/webhooks \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
POST/webhooks

Register a webhook endpoint (HTTPS only). The secret is returned once.

Parameters

Idempotency-Keyheader · string

Request · application/json

FieldTypeNotes
url requiredstring (uri)
events requiredarray of EventTypeminItems 1

Responses

  • 201 Created · WebhookEndpoint + object
curl -X POST https://api.gewapesign.com/api/v1/webhooks \
  -H "Authorization: Bearer $GEWAPESIGN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/gewapesign", "events": ["document.completed"]}'
GET/webhooks/{id}/deliveries

Delivery log for an endpoint (newest first)

Parameters

id requiredpath · string
statusquery · pending | delivered | dead
limitquery · integer

Responses

  • 200 OK · object
  • 404 Error (RFC 9457) · Problem
curl -X GET https://api.gewapesign.com/api/v1/webhooks/doc_.../deliveries \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
POST/webhooks/{id}/deliveries/{delivery_id}/redeliver

Queue a delivery again (for example after fixing your endpoint)

Parameters

id requiredpath · string
delivery_id requiredpath · string

Responses

  • 202 Queued
  • 404 Error (RFC 9457) · Problem
curl -X POST https://api.gewapesign.com/api/v1/webhooks/doc_.../deliveries/<delivery_id>/redeliver \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
DELETE/webhooks/{id}

Remove a webhook endpoint

Parameters

id requiredpath · string

Responses

  • 204 Removed
curl -X DELETE https://api.gewapesign.com/api/v1/webhooks/doc_... \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"

Lifecycle

Billing events in, contracts and approved commands out.

POST/lifecycle/events

Tell GewapeSign what was paid, what renews or what ended

Send one event per billing fact. GewapeSign bundles services paid the same day for the same customer and contracting entity into one contract (configurable), sends renewal contracts before renewals, and keeps chasing unsigned contracts. A payment is never blocked by a missing signature. Duplicate event_ids are ignored (safe to retry).

Parameters

Idempotency-Keyheader · string

Request · application/json

FieldTypeNotes
event_id requiredstring

Unique in your system; duplicates are ignored

type requiredpayment.confirmed | subscription.renewal_upcoming | subscription.terminated
occurred_at requiredstring (date-time)
customer requiredobject
entitystring

Your contracting entity code (one contract never spans two entities)

paymentobject
servicesarray of object

Responses

  • 202 Accepted · object
  • 400 Error (RFC 9457) · Problem
curl -X POST https://api.gewapesign.com/api/v1/lifecycle/events \
  -H "Authorization: Bearer $GEWAPESIGN_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
GET/lifecycle/contracts

Contracts for a customer of yours

Parameters

customer_ref requiredquery · string
statusquery · ContractStatus

Responses

  • 200 OK · object
curl -X GET https://api.gewapesign.com/api/v1/lifecycle/contracts \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
GET/lifecycle/contracts/{id}

One contract with its lines (services, invoices) and document

Parameters

id requiredpath · string

Responses

  • 200 OK · Contract
curl -X GET https://api.gewapesign.com/api/v1/lifecycle/contracts/doc_... \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
GET/lifecycle/commands

Approved actions for your billing system to carry out (pull)

Your connector polls this (or reacts to the command.ready webhook) and executes each command in your billing system, then reports the result. Commands appear here only after approval in GewapeSign, never while your organisation is in dry run, and never while the kill switch is on. Physical services (colocation) always require approval.

Parameters

limitquery · integer

Responses

  • 200 OK · object
curl -X GET https://api.gewapesign.com/api/v1/lifecycle/commands \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"
POST/lifecycle/commands/{id}/result

Report the outcome of a command (idempotent)

Parameters

id requiredpath · string
Idempotency-Keyheader · string

Request · application/json

FieldTypeNotes
ok requiredboolean
errorstringmaxLength 2000
external_refstring

e.g. the voided invoice id in your system

Responses

  • 200 Recorded
curl -X POST https://api.gewapesign.com/api/v1/lifecycle/commands/doc_.../result \
  -H "Authorization: Bearer $GEWAPESIGN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ok": true}'

Account

GET/me

The organisation and mode this key belongs to

Responses

  • 200 OK · Me
  • 401 Error (RFC 9457) · Problem
curl -X GET https://api.gewapesign.com/api/v1/me \
  -H "Authorization: Bearer $GEWAPESIGN_KEY"

Schemas

Problem

FieldTypeNotes
typestring
titlestring
statusinteger
detailstring
request_idstring

Me

FieldTypeNotes
organisationstring
modetest | live
regionstring
dry_runboolean

Lifecycle commands are recorded but never released

Signer

FieldTypeNotes
name requiredstringmaxLength 200
email requiredstring (email)
rolesigner | approver | viewer | ccdefault "signer"
orderinteger

Signing order; equal numbers sign in parallel

minimum 1
statuspending | sent | viewed | signed | declined | expired
signed_atstring | null (date-time)
decline_reasonstring | null

Field

FieldTypeNotes
signer requiredinteger

Signer order this field belongs to

type requiredsignature | initials | name | date | text | checkbox
page requiredintegerminimum 1
x requirednumber

percent of page width

minimum 0, maximum 100
y requirednumberminimum 0, maximum 100
width requirednumberminimum 0, maximum 100
height requirednumberminimum 0, maximum 100

DocumentCreate

FieldTypeNotes
title requiredstringmaxLength 250
external_refstring

Your reference (invoice, deal, ticket); returned in webhooks

maxLength 200
signers requiredarray of SignerminItems 1, maxItems 20
fields requiredarray of Field

Where each signer signs

minItems 1
sequentialbooleandefault true
messagestringmaxLength 2000
sendboolean

Send immediately after creation

default false
expires_in_daysintegerminimum 1, maximum 365
remindersobject

Document

FieldTypeNotes
idstring
titlestring
external_refstring | null
statusDocumentStatus
signersarray of Signer
original_sha256string
signed_sha256string | null
regionstring
created_atstring (date-time)
completed_atstring | null (date-time)

Template

FieldTypeNotes
idstring
namestring
versionstring
variablesarray of string

WebhookEndpoint

FieldTypeNotes
idstring
urlstring
eventsarray of EventType
created_atstring (date-time)

AuditEntry

FieldTypeNotes
atstring (date-time)
actionstring
actorstring
ipstring | null
document_sha256string | null
prev_hashstring
hashstring

LifecycleEvent

FieldTypeNotes
event_id requiredstring

Unique in your system; duplicates are ignored

type requiredpayment.confirmed | subscription.renewal_upcoming | subscription.terminated
occurred_at requiredstring (date-time)
customer requiredobject
entitystring

Your contracting entity code (one contract never spans two entities)

paymentobject
servicesarray of object

Contract

FieldTypeNotes
idstring
customer_refstring
typeinitial | renewal
statusContractStatus
document_idstring | null
linesarray of object
signed_sha256string | null

Command

FieldTypeNotes
idstring
actionvoid_invoice | mark_non_renewing | terminate_at_term_end | reinstate
targetobject
contract_idstring
approved_bystring
approved_atstring (date-time)