{"openapi":"3.0.0","paths":{"/certificates":{"get":{"description":"Use this to find the certificates your organisation has issued, newest first, or to check what is currently in force. Combine filters freely: for example `validity=VALID&scope=ECOWAS` lists the Brown Cards that are in force today.\n\n`q` finds a certificate by its number, or the start of one from the year on (`GH-2026-0004`), by the registration plate in any spacing or case, by the policy number, or by the policyholder's name. Each of these is looked up directly, so a search costs the same however many certificates you hold.\n\nThe list is paged: ask for `limit` certificates (1 to 200, default 50) starting at `offset`. `total` counts matching certificates up to 1,000 and `totalCapped` tells you when more match than that. Each item is a summary; open one certificate for the holder's details and its history.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.read`; choose it when you create the key under Integrations → Integration keys.","operationId":"listCertificates","parameters":[{"name":"q","in":"query","required":false,"description":"Certificate number (or its start), registration plate, policy number or policyholder name.","schema":{"type":"string","maxLength":200},"example":"GR 4821-24"},{"name":"validity","in":"query","required":false,"description":"What the certificate reads as today. `VALID` lists certificates that would pass a check now.","schema":{"type":"string","enum":["VALID","EXPIRED","NOT_YET_VALID","SUSPENDED","CANCELLED","REPLACED"]},"example":"VALID"},{"name":"status","in":"query","required":false,"description":"The status as recorded. `ISSUED`: in force when its dates allow. `SUSPENDED`: paused by the national bureau or the Secretariat. `CANCELLED`: ended by the insurer. `REPLACED`: a newer certificate for the same vehicle took its place. `EXPIRED`: the period of insurance has passed.","schema":{"type":"string","enum":["ISSUED","SUSPENDED","CANCELLED","EXPIRED","REPLACED"]},"example":"ISSUED"},{"name":"scope","in":"query","required":false,"description":"`NATIONAL` or `ECOWAS` (the Brown Card).","schema":{"type":"string","enum":["NATIONAL","ECOWAS"]},"example":"ECOWAS"},{"name":"kind","in":"query","required":false,"description":"`CERTIFICATE` or `COVER_NOTE`.","schema":{"type":"string","enum":["CERTIFICATE","COVER_NOTE"]},"example":"CERTIFICATE"},{"name":"from","in":"query","required":false,"description":"Only certificates issued on or after this day, `YYYY-MM-DD`, UTC.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"example":"2026-10-01"},{"name":"to","in":"query","required":false,"description":"Only certificates issued on or before this day, `YYYY-MM-DD`, UTC.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"example":"2026-10-31"},{"name":"limit","in":"query","required":false,"description":"How many certificates to return, from 1 to 200.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200},"example":50},{"name":"offset","in":"query","required":false,"description":"How many certificates to skip.","schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"example":0}],"responses":{"200":{"description":"A page of certificates.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificatePage"},"examples":{"page":{"summary":"Two certificates","value":{"items":[{"id":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30","number":"GH-2026-0004711","registration":"GR 4821-24","holderName":"Kojo Essien","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"ECOWAS","territories":["BJ","GH","TG"],"kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11","status":"ISSUED","validity":"VALID","source":"API","issuedAt":"2026-10-12T08:14:04.512Z"},{"id":"a19e4c7d-2f60-4b85-9d13-7c5e8b0a6f24","number":"GH-2026-0004698","registration":"GT 3342-25","holderName":"Ama Boateng","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"NATIONAL","territories":["GH"],"kind":"COVER_NOTE","validFrom":"2026-10-10","validTo":"2026-11-08","status":"ISSUED","validity":"VALID","source":"BULK","issuedAt":"2026-10-10T09:02:41.130Z"}],"total":2,"limit":50,"offset":0}}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The key was created without the permission this operation needs.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The key was created without the permission this operation needs.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"You do not have permission to do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"List certificates","tags":["Issue and manage certificates"],"x-integrator":true,"x-permissions":["certificate.read"],"security":[{"apiKey":[]},{"bearer":[]}]},"post":{"description":"Use this to issue one certificate when a policy is bound. The certificate is numbered, signed and counted against your certificate credits at once, and the answer is the whole certificate: its number, the address its QR code opens, and the link to send the policyholder. To issue many certificates in one call, send a batch instead.\n\nA certificate must show what Convention Art. 15(4) requires: the insurer (taken from your key), the policyholder's full name and address, the policy number, the first and last day of the period of insurance, the registration number, the vehicle type, the engine number, the chassis number and the countries covered. If any is blank the call is refused with `ART15_FIELDS_MISSING`, and `errors` names each missing field.\n\n**Period.** Dates are calendar days in UTC, written `YYYY-MM-DD`, with both ends covered. A certificate runs for two years at most. A cover note (`kind: \"COVER_NOTE\"`) is valid for one month at most: a cover note starting on 12 October ends on 11 November at the latest.\n\n**Countries covered.** `NATIONAL` covers the issuing country. `ECOWAS` is the Brown Card: it covers the member states listed in `territories`, which must include your own country and at least one other, and covers all fifteen when left out.\n\n**Retrying safely.** Send an `Idempotency-Key`. If the call is repeated with the same key, for example after a timeout, you receive the certificate the first call issued, with `replayed: true`, and no second certificate or credit is used.\n\n**Credits.** Each certificate uses one credit. With none left the call is refused with `STOCK_EMPTY`; read your balance with **Get your certificate credits**.\n\nOnly an active insurer in good standing can issue.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.issue`; choose it when you create the key under Integrations → Integration keys.","operationId":"issueCertificate","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose and keep for this request, up to 200 characters. Send the same value when you retry and you get the original result back instead of a second one. Use a new value for each new request, for example the policy reference with the cover start date.","schema":{"type":"string","minLength":1,"maxLength":200},"example":"policy-GH-7781204-2026-10-12"}],"requestBody":{"required":true,"description":"The certificate to issue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueCertificate"},"examples":{"brownCard":{"summary":"A Brown Card for Ghana, Togo and Benin","value":{"policyNumber":"POL-GH-7781204","holder":{"type":"PERSON","name":"Kojo Essien","address":"Spintex Road, Accra","phone":"+233244310001","email":"kojo.essien@example.org"},"vehicle":{"registration":"GR 4821-24","vin":"JTNBE40K703118426","engineNumber":"1NZ-3492017","make":"Toyota","model":"Corolla","category":"CAR","use":"PRIVATE"},"scope":"ECOWAS","territories":["GH","TG","BJ"],"kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11"}},"national":{"summary":"A national certificate for a company vehicle in Togo","value":{"policyNumber":"POL-TG-0045120","holder":{"type":"COMPANY","name":"Transports Agbeko SARL","address":"Boulevard du 13 Janvier, Lomé"},"vehicle":{"registration":"TG 1234 AB","vin":"WDB9634031L842019","engineNumber":"OM457-9061152","category":"TRUCK","use":"COMMERCIAL"},"scope":"NATIONAL","kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11"}},"coverNote":{"summary":"A one-month cover note","value":{"policyNumber":"POL-GH-7781311","holder":{"name":"Ama Boateng","address":"Adum, Kumasi"},"vehicle":{"registration":"AS 2210-23","vin":"MHFXW42G603061877","engineNumber":"2KD-5503816","category":"PICKUP"},"scope":"NATIONAL","kind":"COVER_NOTE","validFrom":"2026-10-12","validTo":"2026-11-11"}}}}}},"responses":{"201":{"description":"The certificate was issued, or, when `replayed` is true, it had been issued by an earlier call with the same `Idempotency-Key`.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Certificate"},"examples":{"issued":{"summary":"Issued","value":{"id":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30","number":"GH-2026-0004711","registration":"GR 4821-24","holderName":"Kojo Essien","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"ECOWAS","territories":["BJ","GH","TG"],"kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11","status":"ISSUED","validity":"VALID","source":"API","issuedAt":"2026-10-12T08:14:04.512Z","version":1,"policyId":"d4a8c7e1-6b25-4f93-8e0a-1c7b9f3d5a62","policyNumber":"POL-GH-7781204","holder":{"ref":"5be1f2a9-0c47-4d38-a6b1-9e2d7c4f8a03","type":"PERSON","name":"Kojo Essien","address":"Spintex Road, Accra","phone":"+233244310001","email":"kojo.essien@example.org"},"vehicle":{"registration":"GR 4821-24","vin":"JTNBE40K703118426","engineNumber":"1NZ-3492017","make":"Toyota","model":"Corolla","category":"CAR","use":"PRIVATE"},"insurer":{"id":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","code":"GH-VOLTA","name":"Volta Assurance","country":"GH","address":"Ring Road Central, Accra"},"keyId":"GH-2026-1","qrUrl":"https://browncard.example/v/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIiwiciI6IkdSIDQ4MjEtMjQiLCJpIjoiR0gtVk9MVEEiLCJjIjoiR0giLCJzIjoiRUNPV0FTIiwidCI6IkJKLEdILFRHIiwiZiI6IjIwMjYtMTAtMTIiLCJ1IjoiMjAyNy0xMC0xMSIsInYiOjEsImsiOiJDRVJUSUZJQ0FURSJ9.AZX4kT5sTBqJm8hQdIEJwH999zI4jS6IqOy1-8x8jcREwEcLy_PwA5j-t-bkSYhqtGoDAVn2S8mkcR863Z3eAA","holderLink":"https://browncard.example/c/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIn0.k3fT9Qm2","renewalOf":null,"renewedBy":null,"requestId":null,"sourceSystem":null,"issuedBy":"api_client:key:7d2c91ab-35e0-4f68-b1a4-60c8d2e9f357"}},"replayed":{"summary":"The same call repeated","description":"The certificate from the first call is returned and no credit is used.","value":{"id":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30","number":"GH-2026-0004711","registration":"GR 4821-24","holderName":"Kojo Essien","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"ECOWAS","territories":["BJ","GH","TG"],"kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11","status":"ISSUED","validity":"VALID","source":"API","issuedAt":"2026-10-12T08:14:04.512Z","version":1,"policyId":"d4a8c7e1-6b25-4f93-8e0a-1c7b9f3d5a62","policyNumber":"POL-GH-7781204","holder":{"ref":"5be1f2a9-0c47-4d38-a6b1-9e2d7c4f8a03","type":"PERSON","name":"Kojo Essien","address":"Spintex Road, Accra","phone":"+233244310001","email":"kojo.essien@example.org"},"vehicle":{"registration":"GR 4821-24","vin":"JTNBE40K703118426","engineNumber":"1NZ-3492017","make":"Toyota","model":"Corolla","category":"CAR","use":"PRIVATE"},"insurer":{"id":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","code":"GH-VOLTA","name":"Volta Assurance","country":"GH","address":"Ring Road Central, Accra"},"keyId":"GH-2026-1","qrUrl":"https://browncard.example/v/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIiwiciI6IkdSIDQ4MjEtMjQiLCJpIjoiR0gtVk9MVEEiLCJjIjoiR0giLCJzIjoiRUNPV0FTIiwidCI6IkJKLEdILFRHIiwiZiI6IjIwMjYtMTAtMTIiLCJ1IjoiMjAyNy0xMC0xMSIsInYiOjEsImsiOiJDRVJUSUZJQ0FURSJ9.AZX4kT5sTBqJm8hQdIEJwH999zI4jS6IqOy1-8x8jcREwEcLy_PwA5j-t-bkSYhqtGoDAVn2S8mkcR863Z3eAA","holderLink":"https://browncard.example/c/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIn0.k3fT9Qm2","renewalOf":null,"renewedBy":null,"requestId":null,"sourceSystem":null,"issuedBy":"api_client:key:7d2c91ab-35e0-4f68-b1a4-60c8d2e9f357","replayed":true}}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `ART15_FIELDS_MISSING`: A required item is blank.\n- `COVER_NOTE_TOO_LONG`: A cover note is longer than one month. `PERIOD_TOO_LONG` is the same for a certificate longer than two years, `PERIOD_ORDER` for an end before the start, `INVALID_DATE` for a date that does not exist.\n- `TERRITORY_MISSING_ISSUER`: `territories` leaves out your own country. `TERRITORY_TOO_FEW` is returned for a list of one country and `UNKNOWN_TERRITORY` for a code that is not a member state.\n- `IDEMPOTENCY_KEY`: The `Idempotency-Key` is empty or longer than 200 characters.\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ART15_FIELDS_MISSING":{"summary":"400 ART15_FIELDS_MISSING","description":"A required item is blank.","value":{"type":"urn:bc:problem:art15_fields_missing","title":"Bad request","status":400,"code":"ART15_FIELDS_MISSING","detail":"A certificate must show the policyholder's address.","errors":[{"path":"holder.address","message":"Required on the certificate"}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"COVER_NOTE_TOO_LONG":{"summary":"400 COVER_NOTE_TOO_LONG","description":"A cover note is longer than one month. `PERIOD_TOO_LONG` is the same for a certificate longer than two years, `PERIOD_ORDER` for an end before the start, `INVALID_DATE` for a date that does not exist.","value":{"type":"urn:bc:problem:cover_note_too_long","title":"Bad request","status":400,"code":"COVER_NOTE_TOO_LONG","detail":"A cover note is valid for one month at most. End it on 2026-11-11 or earlier.","errors":[{"path":"validTo","message":"A cover note is valid for one month at most. End it on 2026-11-11 or earlier."}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"TERRITORY_MISSING_ISSUER":{"summary":"400 TERRITORY_MISSING_ISSUER","description":"`territories` leaves out your own country. `TERRITORY_TOO_FEW` is returned for a list of one country and `UNKNOWN_TERRITORY` for a code that is not a member state.","value":{"type":"urn:bc:problem:territory_missing_issuer","title":"Bad request","status":400,"code":"TERRITORY_MISSING_ISSUER","detail":"The countries covered must include the issuing country.","errors":[{"path":"territories","message":"The countries covered must include the issuing country."}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"IDEMPOTENCY_KEY":{"summary":"400 IDEMPOTENCY_KEY","description":"The `Idempotency-Key` is empty or longer than 200 characters.","value":{"type":"urn:bc:problem:idempotency_key","title":"Bad request","status":400,"code":"IDEMPOTENCY_KEY","detail":"The Idempotency-Key header must be 1 to 200 characters.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","errors":[{"path":"policyNumber","message":"Invalid input: expected string, received undefined"}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The key does not carry `certificate.issue`, or its organisation is not an insurer.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The key does not carry `certificate.issue`, or its organisation is not an insurer.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"Only an insurer issues certificates.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"409":{"description":"Conflict. The `code` in the body says which of these it is.\n\n- `INSURER_SUSPENDED`: The insurer is suspended. `INSURER_NOT_IN_GOOD_STANDING` is returned for an insurer the national bureau has not kept in good standing.\n- `STOCK_EMPTY`: The insurer has no certificate credits left.\n- `VEHICLE_ALREADY_COVERED`: Another insurer already has a certificate or cover note in force for this vehicle on one of the days requested.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"INSURER_SUSPENDED":{"summary":"409 INSURER_SUSPENDED","description":"The insurer is suspended. `INSURER_NOT_IN_GOOD_STANDING` is returned for an insurer the national bureau has not kept in good standing.","value":{"type":"urn:bc:problem:insurer_suspended","title":"Conflict","status":409,"code":"INSURER_SUSPENDED","detail":"Volta Assurance is suspended and cannot issue certificates. Contact your national bureau.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"STOCK_EMPTY":{"summary":"409 STOCK_EMPTY","description":"The insurer has no certificate credits left.","value":{"type":"urn:bc:problem:stock_empty","title":"Conflict","status":409,"code":"STOCK_EMPTY","detail":"You have no certificate credits left. Order more from your national bureau under Stock.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"VEHICLE_ALREADY_COVERED":{"summary":"409 VEHICLE_ALREADY_COVERED","description":"Another insurer already has a certificate or cover note in force for this vehicle on one of the days requested.","value":{"type":"urn:bc:problem:vehicle_already_covered","title":"Conflict","status":409,"code":"VEHICLE_ALREADY_COVERED","detail":"GR 4821-24 is already covered by Adinkra General Insurance until 2027-03-01. A new certificate can start on 2027-03-02.","errors":[{"path":"validFrom","message":"Covered by Adinkra General Insurance until 2027-03-01"}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Issue a certificate","tags":["Issue and manage certificates"],"x-integrator":true,"x-permissions":["certificate.issue"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/certificates/suspend-batch":{"post":{"operationId":"CertificatesController_suspendBatch","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"insurerOrgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["insurerOrgId","reason"],"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["certificates"],"x-permissions":["certificate.suspend"]}},"/certificates/reinstate-batch":{"post":{"operationId":"CertificatesController_reinstateBatch","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"insurerOrgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["insurerOrgId","reason"],"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["certificates"],"x-permissions":["certificate.reinstate"]}},"/certificates/batches/{id}":{"get":{"operationId":"CertificatesController_batch","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["certificates"],"x-permissions":["certificate.read"]}},"/certificates/by-token/{token}":{"get":{"operationId":"CertificatesController_byToken","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["certificates"],"x-public":true}},"/certificates/by-token/{token}/pdf":{"get":{"operationId":"CertificatesController_byTokenPdf","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["certificates"],"x-public":true}},"/certificates/by-token/{token}/card.png":{"get":{"operationId":"CertificatesController_byTokenCard","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["certificates"],"x-public":true}},"/certificates/public/{ref}/card.png":{"get":{"description":"Use this to show a certificate to someone who is not the holder or the insurer, for example on a verification screen or a roadside check. Anyone holding the certificate number or the address in its QR code can fetch it, with no key.\n\nThe picture is the card without the policyholder's name and address, the policy number, or the chassis and engine numbers, so it is safe to display publicly. Pass either the certificate number (`GH-2026-0004711`) or the signed code from the QR address. A Brown Card has a front and a back; a national certificate has a front only.\n\nPictures are drawn on demand and shared for a minute, so repeated requests are cheap. This route allows 30 requests a minute from one address.\n\n**Access.** Open to everyone. No key is needed.","operationId":"getPublicCertificateCard","parameters":[{"name":"ref","in":"path","required":true,"description":"The certificate number, or the signed code that follows `/v/` in the QR address.","schema":{"type":"string"},"example":"GH-2026-0004711"},{"name":"face","in":"query","required":false,"description":"Which side of the card: `front` (the default) or `back`.","schema":{"default":"front","type":"string","enum":["front","back"]},"example":"front"},{"name":"lang","in":"query","required":false,"description":"The language of the document: `en`, `fr` or `pt`. Defaults to the holder’s language, then English.","schema":{"type":"string","enum":["en","fr","pt"]},"example":"en"},{"name":"scale","in":"query","required":false,"description":"`1` for the size of the printed form, `2` (the default) for twice that.","schema":{"type":"string","enum":["1","2"]},"example":"2"}],"responses":{"200":{"description":"The public card as a PNG image.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"cache-control":{"description":"Shared for one minute.","schema":{"type":"string"},"example":"public, max-age=60"}},"content":{"image/png":{"schema":{"type":"string","format":"binary"},"examples":{"image":{"summary":"A PNG image","value":"(PNG image of the card)"}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"404":{"description":"Not found. The `code` in the body says which of these it is.\n\n- `NOT_FOUND`: The certificate does not exist, or belongs to another organisation.\n- `NO_BACK`: The back of a national certificate was requested.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"NOT_FOUND":{"summary":"404 NOT_FOUND","description":"The certificate does not exist, or belongs to another organisation.","value":{"type":"urn:bc:problem:not_found","title":"Not found","status":404,"code":"NOT_FOUND","detail":"the certificate was not found.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"NO_BACK":{"summary":"404 NO_BACK","description":"The back of a national certificate was requested.","value":{"type":"urn:bc:problem:no_back","title":"Not found","status":404,"code":"NO_BACK","detail":"This certificate has a single face.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests from this address. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Get the public picture of a certificate card","tags":["Documents and pictures"],"x-integrator":true,"x-public":true,"security":[]}},"/certificates/authority/{ref}/card.png":{"get":{"operationId":"CertificatesController_authorityCard","parameters":[{"name":"ref","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["certificates"],"x-permissions":["verify.authority"]}},"/certificates/{id}":{"get":{"description":"Use this to read one certificate in full: the policyholder and vehicle details as printed, the period and territories, the address its QR code opens, the link for the policyholder, and the history of every change.\n\n`validity` tells you what a check made today would say. It follows the status, then the dates: a certificate is `NOT_YET_VALID` before `validFrom`, `VALID` through `validTo`, and `EXPIRED` after it, unless it was suspended, cancelled or replaced.\n\nThe policyholder's phone number, email address and link are shown to the issuing insurer and to the policyholder; other readers receive them empty.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.read`; choose it when you create the key under Integrations → Integration keys.","operationId":"getCertificate","parameters":[{"name":"id","in":"path","required":true,"description":"The id of the certificate: the `id` in the answer to issuing it or in the list.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"example":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30"}],"responses":{"200":{"description":"The certificate with its history.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Certificate"},"examples":{"certificate":{"summary":"A certificate in force","value":{"id":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30","number":"GH-2026-0004711","registration":"GR 4821-24","holderName":"Kojo Essien","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"ECOWAS","territories":["BJ","GH","TG"],"kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11","status":"ISSUED","validity":"VALID","source":"API","issuedAt":"2026-10-12T08:14:04.512Z","version":1,"policyId":"d4a8c7e1-6b25-4f93-8e0a-1c7b9f3d5a62","policyNumber":"POL-GH-7781204","holder":{"ref":"5be1f2a9-0c47-4d38-a6b1-9e2d7c4f8a03","type":"PERSON","name":"Kojo Essien","address":"Spintex Road, Accra","phone":"+233244310001","email":"kojo.essien@example.org"},"vehicle":{"registration":"GR 4821-24","vin":"JTNBE40K703118426","engineNumber":"1NZ-3492017","make":"Toyota","model":"Corolla","category":"CAR","use":"PRIVATE"},"insurer":{"id":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","code":"GH-VOLTA","name":"Volta Assurance","country":"GH","address":"Ring Road Central, Accra"},"keyId":"GH-2026-1","qrUrl":"https://browncard.example/v/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIiwiciI6IkdSIDQ4MjEtMjQiLCJpIjoiR0gtVk9MVEEiLCJjIjoiR0giLCJzIjoiRUNPV0FTIiwidCI6IkJKLEdILFRHIiwiZiI6IjIwMjYtMTAtMTIiLCJ1IjoiMjAyNy0xMC0xMSIsInYiOjEsImsiOiJDRVJUSUZJQ0FURSJ9.AZX4kT5sTBqJm8hQdIEJwH999zI4jS6IqOy1-8x8jcREwEcLy_PwA5j-t-bkSYhqtGoDAVn2S8mkcR863Z3eAA","holderLink":"https://browncard.example/c/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIn0.k3fT9Qm2","renewalOf":null,"renewedBy":null,"requestId":null,"sourceSystem":null,"issuedBy":"api_client:key:7d2c91ab-35e0-4f68-b1a4-60c8d2e9f357","history":[{"action":"ISSUED","reason":null,"actor":"api_client:key:7d2c91ab-35e0-4f68-b1a4-60c8d2e9f357","at":"2026-10-12T08:14:04.512Z","version":1,"statusAfter":"ISSUED"}]}}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The key was created without the permission this operation needs.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The key was created without the permission this operation needs.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"You do not have permission to do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"404":{"description":"Not found. The `code` in the body says which of these it is.\n\n- `NOT_FOUND`: The certificate does not exist, or belongs to another organisation.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"NOT_FOUND":{"summary":"404 NOT_FOUND","description":"The certificate does not exist, or belongs to another organisation.","value":{"type":"urn:bc:problem:not_found","title":"Not found","status":404,"code":"NOT_FOUND","detail":"the certificate was not found.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Get a certificate","tags":["Issue and manage certificates"],"x-integrator":true,"x-permissions":["certificate.read"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/certificates/{id}/pdf":{"get":{"description":"Use this to print a certificate or attach it to a message. The PDF shows the whole certificate with its QR code. A Brown Card is laid out on the official form with a front and a back page; a national certificate is a single page.\n\nThe answer is the file itself, `application/pdf`, to display or save. Choose the language of the printed labels with `lang`; without it the holder's language is used.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.read`; choose it when you create the key under Integrations → Integration keys.","operationId":"getCertificatePdf","parameters":[{"name":"id","in":"path","required":true,"description":"The id of the certificate: the `id` in the answer to issuing it or in the list.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"example":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30"},{"name":"lang","in":"query","required":false,"description":"The language of the document: `en`, `fr` or `pt`. Defaults to the holder’s language, then English.","schema":{"type":"string","enum":["en","fr","pt"]},"example":"en"}],"responses":{"200":{"description":"The certificate as a PDF file.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"content-disposition":{"description":"Names the file after the certificate number.","schema":{"type":"string"},"example":"inline; filename=\"GH-2026-0004711.pdf\""}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"},"examples":{"file":{"summary":"A PDF file","value":"(PDF file, GH-2026-0004711.pdf)"}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The key was created without the permission this operation needs.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The key was created without the permission this operation needs.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"You do not have permission to do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"404":{"description":"Not found. The `code` in the body says which of these it is.\n\n- `NOT_FOUND`: The certificate does not exist, or belongs to another organisation.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"NOT_FOUND":{"summary":"404 NOT_FOUND","description":"The certificate does not exist, or belongs to another organisation.","value":{"type":"urn:bc:problem:not_found","title":"Not found","status":404,"code":"NOT_FOUND","detail":"the certificate was not found.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Download a certificate as a PDF","tags":["Documents and pictures"],"x-integrator":true,"x-permissions":["certificate.read"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/certificates/{id}/card.png":{"get":{"description":"Use this to show a certificate on a screen: the card as a PNG picture, front or back, with all of its details. A Brown Card has a front and a back; a national certificate has a front only, and asking for its back answers `NO_BACK`.\n\nThe picture is drawn when asked for and shows the certificate's current status. It is for the staff and the policyholder; to show a certificate to anyone else use the public picture, which leaves out personal details.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.read`; choose it when you create the key under Integrations → Integration keys.","operationId":"getCertificateCard","parameters":[{"name":"id","in":"path","required":true,"description":"The id of the certificate: the `id` in the answer to issuing it or in the list.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"example":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30"},{"name":"face","in":"query","required":false,"description":"Which side of the card: `front` (the default) or `back`.","schema":{"default":"front","type":"string","enum":["front","back"]},"example":"front"},{"name":"lang","in":"query","required":false,"description":"The language of the document: `en`, `fr` or `pt`. Defaults to the holder’s language, then English.","schema":{"type":"string","enum":["en","fr","pt"]},"example":"en"},{"name":"scale","in":"query","required":false,"description":"`1` for the size of the printed form, `2` (the default) for twice that, for sharp screens.","schema":{"type":"string","enum":["1","2"]},"example":"2"}],"responses":{"200":{"description":"The card as a PNG image.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"image/png":{"schema":{"type":"string","format":"binary"},"examples":{"image":{"summary":"A PNG image","value":"(PNG image of the card)"}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The key was created without the permission this operation needs.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The key was created without the permission this operation needs.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"You do not have permission to do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"404":{"description":"Not found. The `code` in the body says which of these it is.\n\n- `NOT_FOUND`: The certificate does not exist, or belongs to another organisation.\n- `NO_BACK`: The back of a national certificate was requested.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"NOT_FOUND":{"summary":"404 NOT_FOUND","description":"The certificate does not exist, or belongs to another organisation.","value":{"type":"urn:bc:problem:not_found","title":"Not found","status":404,"code":"NOT_FOUND","detail":"the certificate was not found.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"NO_BACK":{"summary":"404 NO_BACK","description":"The back of a national certificate was requested.","value":{"type":"urn:bc:problem:no_back","title":"Not found","status":404,"code":"NO_BACK","detail":"This certificate has a single face.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Get a picture of the certificate card","tags":["Documents and pictures"],"x-integrator":true,"x-permissions":["certificate.read"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/certificates/{id}/image.png":{"get":{"operationId":"CertificatesController_image","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["certificates"],"x-permissions":["certificate.read"]}},"/certificates/{id}/renew":{"post":{"description":"Use this when a policy continues: it issues a new certificate for the next period, linked to the one it renews, with the same policyholder, vehicle and territories. It uses one certificate credit.\n\nWithout a body the new period starts the day after the old one ends (or today, if the old one has already ended) and runs for one year, or one month for a cover note. Send `validFrom`, `validTo` or `kind` to choose another period or to turn a cover note into a certificate. The same period rules apply as when issuing: two years at most for a certificate and one month for a cover note.\n\nA renewal that starts before the old certificate ends takes its place, and the old one reads as `REPLACED`. A renewal that starts after it leaves the old one to run out. The old certificate shows the number of the new one in `renewedBy`.\n\nOnly the insurer that issued the certificate can renew it. A cancelled or replaced certificate cannot be renewed; issue a new one instead. Renewing has no idempotency key: if a call times out, read the certificate and look at `renewedBy` before calling again.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.renew`; choose it when you create the key under Integrations → Integration keys.","operationId":"renewCertificate","parameters":[{"name":"id","in":"path","required":true,"description":"The id of the certificate: the `id` in the answer to issuing it or in the list.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"example":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenewCertificate"},"examples":{"defaults":{"summary":"The usual renewal for one more year","value":{}},"period":{"summary":"A chosen period","value":{"validFrom":"2027-10-12","validTo":"2028-10-11"}}}}}},"responses":{"201":{"description":"The new certificate.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Certificate"},"examples":{"renewed":{"summary":"The renewal","value":{"id":"c60b3e1d-8a47-4f29-b5d0-2e9a7f14c853","number":"GH-2027-0000412","registration":"GR 4821-24","holderName":"Kojo Essien","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"ECOWAS","territories":["BJ","GH","TG"],"kind":"CERTIFICATE","validFrom":"2027-10-12","validTo":"2028-10-11","status":"ISSUED","validity":"NOT_YET_VALID","source":"API","issuedAt":"2027-09-20T10:31:12.044Z","version":1,"policyId":"d4a8c7e1-6b25-4f93-8e0a-1c7b9f3d5a62","policyNumber":"POL-GH-7781204","holder":{"ref":"5be1f2a9-0c47-4d38-a6b1-9e2d7c4f8a03","type":"PERSON","name":"Kojo Essien","address":"Spintex Road, Accra","phone":"+233244310001","email":"kojo.essien@example.org"},"vehicle":{"registration":"GR 4821-24","vin":"JTNBE40K703118426","engineNumber":"1NZ-3492017","make":"Toyota","model":"Corolla","category":"CAR","use":"PRIVATE"},"insurer":{"id":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","code":"GH-VOLTA","name":"Volta Assurance","country":"GH","address":"Ring Road Central, Accra"},"keyId":"GH-2026-1","qrUrl":"https://browncard.example/v/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIiwiciI6IkdSIDQ4MjEtMjQiLCJpIjoiR0gtVk9MVEEiLCJjIjoiR0giLCJzIjoiRUNPV0FTIiwidCI6IkJKLEdILFRHIiwiZiI6IjIwMjYtMTAtMTIiLCJ1IjoiMjAyNy0xMC0xMSIsInYiOjEsImsiOiJDRVJUSUZJQ0FURSJ9.AZX4kT5sTBqJm8hQdIEJwH999zI4jS6IqOy1-8x8jcREwEcLy_PwA5j-t-bkSYhqtGoDAVn2S8mkcR863Z3eAA","holderLink":"https://browncard.example/c/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIn0.k3fT9Qm2","renewalOf":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30","renewedBy":null,"requestId":null,"sourceSystem":null,"issuedBy":"api_client:key:7d2c91ab-35e0-4f68-b1a4-60c8d2e9f357"}}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","errors":[{"path":"validFrom","message":"Invalid input: expected string, received undefined"}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The certificate was issued by another insurer, or the key does not carry `certificate.renew`.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The certificate was issued by another insurer, or the key does not carry `certificate.renew`.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"Only the issuing insurer can do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"404":{"description":"Not found. The `code` in the body says which of these it is.\n\n- `NOT_FOUND`: The certificate does not exist, or belongs to another organisation.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"NOT_FOUND":{"summary":"404 NOT_FOUND","description":"The certificate does not exist, or belongs to another organisation.","value":{"type":"urn:bc:problem:not_found","title":"Not found","status":404,"code":"NOT_FOUND","detail":"the certificate was not found.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"409":{"description":"Conflict. The `code` in the body says which of these it is.\n\n- `CERTIFICATE_CANCELLED`: The certificate was cancelled. `CERTIFICATE_REPLACED` is returned for one that a newer certificate replaced.\n- `STOCK_EMPTY`: The insurer has no certificate credits left.\n- `INSURER_SUSPENDED`: The insurer is suspended. `INSURER_NOT_IN_GOOD_STANDING` is returned for an insurer the national bureau has not kept in good standing.\n- `VEHICLE_ALREADY_COVERED`: Another insurer has a certificate or cover note in force for this vehicle on one of the days of the new period.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"CERTIFICATE_CANCELLED":{"summary":"409 CERTIFICATE_CANCELLED","description":"The certificate was cancelled. `CERTIFICATE_REPLACED` is returned for one that a newer certificate replaced.","value":{"type":"urn:bc:problem:certificate_cancelled","title":"Conflict","status":409,"code":"CERTIFICATE_CANCELLED","detail":"A cancelled certificate cannot be renewed. Issue a new one.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"STOCK_EMPTY":{"summary":"409 STOCK_EMPTY","description":"The insurer has no certificate credits left.","value":{"type":"urn:bc:problem:stock_empty","title":"Conflict","status":409,"code":"STOCK_EMPTY","detail":"You have no certificate credits left. Order more from your national bureau under Stock.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"INSURER_SUSPENDED":{"summary":"409 INSURER_SUSPENDED","description":"The insurer is suspended. `INSURER_NOT_IN_GOOD_STANDING` is returned for an insurer the national bureau has not kept in good standing.","value":{"type":"urn:bc:problem:insurer_suspended","title":"Conflict","status":409,"code":"INSURER_SUSPENDED","detail":"Volta Assurance is suspended and cannot issue certificates. Contact your national bureau.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"VEHICLE_ALREADY_COVERED":{"summary":"409 VEHICLE_ALREADY_COVERED","description":"Another insurer has a certificate or cover note in force for this vehicle on one of the days of the new period.","value":{"type":"urn:bc:problem:vehicle_already_covered","title":"Conflict","status":409,"code":"VEHICLE_ALREADY_COVERED","detail":"GR 4821-24 is already covered by Adinkra General Insurance until 2027-03-01. A new certificate can start on 2027-03-02.","errors":[{"path":"validFrom","message":"Covered by Adinkra General Insurance until 2027-03-01"}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Renew a certificate","tags":["Issue and manage certificates"],"x-integrator":true,"x-permissions":["certificate.renew"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/certificates/{id}/cancel":{"post":{"description":"Use this when the insurer ends the cover before its last day, for example when a policy is cancelled or was issued in error. From that moment a check of the certificate or its QR code answers `CANCELLED`. Cancelling cannot be undone; to cover the vehicle again, issue a new certificate.\n\nA reason of at least three characters is required and is kept in the certificate's history. A certificate in force or suspended can be cancelled; one that is already cancelled, expired or replaced cannot.\n\nOnly the insurer that issued the certificate can cancel it. The credit the certificate used is not returned.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.cancel`; choose it when you create the key under Integrations → Integration keys.","operationId":"cancelCertificate","parameters":[{"name":"id","in":"path","required":true,"description":"The id of the certificate: the `id` in the answer to issuing it or in the list.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"example":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelCertificate"},"examples":{"cancel":{"summary":"Cancelled at the holder’s request","value":{"reason":"Policy cancelled at the policyholder’s request"}}}}}},"responses":{"201":{"description":"The certificate, now cancelled.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Certificate"},"examples":{"cancelled":{"summary":"Cancelled","value":{"id":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30","number":"GH-2026-0004711","registration":"GR 4821-24","holderName":"Kojo Essien","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"ECOWAS","territories":["BJ","GH","TG"],"kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11","status":"CANCELLED","validity":"CANCELLED","source":"API","issuedAt":"2026-10-12T08:14:04.512Z","version":1,"policyId":"d4a8c7e1-6b25-4f93-8e0a-1c7b9f3d5a62","policyNumber":"POL-GH-7781204","holder":{"ref":"5be1f2a9-0c47-4d38-a6b1-9e2d7c4f8a03","type":"PERSON","name":"Kojo Essien","address":"Spintex Road, Accra","phone":"+233244310001","email":"kojo.essien@example.org"},"vehicle":{"registration":"GR 4821-24","vin":"JTNBE40K703118426","engineNumber":"1NZ-3492017","make":"Toyota","model":"Corolla","category":"CAR","use":"PRIVATE"},"insurer":{"id":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","code":"GH-VOLTA","name":"Volta Assurance","country":"GH","address":"Ring Road Central, Accra"},"keyId":"GH-2026-1","qrUrl":"https://browncard.example/v/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIiwiciI6IkdSIDQ4MjEtMjQiLCJpIjoiR0gtVk9MVEEiLCJjIjoiR0giLCJzIjoiRUNPV0FTIiwidCI6IkJKLEdILFRHIiwiZiI6IjIwMjYtMTAtMTIiLCJ1IjoiMjAyNy0xMC0xMSIsInYiOjEsImsiOiJDRVJUSUZJQ0FURSJ9.AZX4kT5sTBqJm8hQdIEJwH999zI4jS6IqOy1-8x8jcREwEcLy_PwA5j-t-bkSYhqtGoDAVn2S8mkcR863Z3eAA","holderLink":"https://browncard.example/c/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIn0.k3fT9Qm2","renewalOf":null,"renewedBy":null,"requestId":null,"sourceSystem":null,"issuedBy":"api_client:key:7d2c91ab-35e0-4f68-b1a4-60c8d2e9f357"}}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","errors":[{"path":"reason","message":"Invalid input: expected string, received undefined"}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The certificate was issued by another insurer, or the key does not carry `certificate.cancel`.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The certificate was issued by another insurer, or the key does not carry `certificate.cancel`.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"Only the issuing insurer can do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"404":{"description":"Not found. The `code` in the body says which of these it is.\n\n- `NOT_FOUND`: The certificate does not exist, or belongs to another organisation.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"NOT_FOUND":{"summary":"404 NOT_FOUND","description":"The certificate does not exist, or belongs to another organisation.","value":{"type":"urn:bc:problem:not_found","title":"Not found","status":404,"code":"NOT_FOUND","detail":"the certificate was not found.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"409":{"description":"Conflict. The `code` in the body says which of these it is.\n\n- `INVALID_STATUS`: The certificate is not in force or suspended.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"INVALID_STATUS":{"summary":"409 INVALID_STATUS","description":"The certificate is not in force or suspended.","value":{"type":"urn:bc:problem:invalid_status","title":"Conflict","status":409,"code":"INVALID_STATUS","detail":"This certificate is cancelled and cannot be cancelled.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Cancel a certificate","tags":["Issue and manage certificates"],"x-integrator":true,"x-permissions":["certificate.cancel"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/certificates/{id}/suspend":{"post":{"operationId":"CertificatesController_suspend","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["reason"],"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["certificates"],"x-permissions":["certificate.suspend"]}},"/certificates/{id}/reinstate":{"post":{"operationId":"CertificatesController_reinstate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["reason"],"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["certificates"],"x-permissions":["certificate.reinstate"]}},"/certificates/{id}/duplicate":{"post":{"description":"Use this when a policyholder has lost the certificate or needs a fresh copy (Convention Art. 20). The certificate keeps its number, period and details; its version rises by one and it is signed again, so the QR code on the new copy differs from the earlier one. QR codes already printed keep verifying, and the link sent to the holder earlier stops working: send the new `holderLink`.\n\nOnly a certificate in force can be duplicated. A reason is optional and is kept in the history. A duplicate uses no certificate credit.\n\nOnly the insurer that issued the certificate can ask for a duplicate. This operation needs the permission `certificate.duplicate`, which integration keys cannot carry: call it with the session token of a signed-in insurer user, sent as a bearer token.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `certificate.duplicate`; choose it when you create the key under Integrations → Integration keys.","operationId":"duplicateCertificate","parameters":[{"name":"id","in":"path","required":true,"description":"The id of the certificate: the `id` in the answer to issuing it or in the list.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"example":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateCertificate"},"examples":{"lost":{"summary":"A lost certificate","value":{"reason":"Certificate lost; holder asked for a copy"}}}}}},"responses":{"201":{"description":"The certificate with its new version.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Certificate"},"examples":{"duplicated":{"summary":"Version 2","value":{"id":"7c1f0a52-3a8e-4b8d-9f6e-2d4a9c1b7e30","number":"GH-2026-0004711","registration":"GR 4821-24","holderName":"Kojo Essien","insurerOrgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","insurerName":"Volta Assurance","insurerCode":"GH-VOLTA","country":"GH","scope":"ECOWAS","territories":["BJ","GH","TG"],"kind":"CERTIFICATE","validFrom":"2026-10-12","validTo":"2027-10-11","status":"ISSUED","validity":"VALID","source":"API","issuedAt":"2026-10-12T08:14:04.512Z","version":2,"policyId":"d4a8c7e1-6b25-4f93-8e0a-1c7b9f3d5a62","policyNumber":"POL-GH-7781204","holder":{"ref":"5be1f2a9-0c47-4d38-a6b1-9e2d7c4f8a03","type":"PERSON","name":"Kojo Essien","address":"Spintex Road, Accra","phone":"+233244310001","email":"kojo.essien@example.org"},"vehicle":{"registration":"GR 4821-24","vin":"JTNBE40K703118426","engineNumber":"1NZ-3492017","make":"Toyota","model":"Corolla","category":"CAR","use":"PRIVATE"},"insurer":{"id":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","code":"GH-VOLTA","name":"Volta Assurance","country":"GH","address":"Ring Road Central, Accra"},"keyId":"GH-2026-1","qrUrl":"https://browncard.example/v/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIiwiciI6IkdSIDQ4MjEtMjQiLCJpIjoiR0gtVk9MVEEiLCJjIjoiR0giLCJzIjoiRUNPV0FTIiwidCI6IkJKLEdILFRHIiwiZiI6IjIwMjYtMTAtMTIiLCJ1IjoiMjAyNy0xMC0xMSIsInYiOjEsImsiOiJDRVJUSUZJQ0FURSJ9.AZX4kT5sTBqJm8hQdIEJwH999zI4jS6IqOy1-8x8jcREwEcLy_PwA5j-t-bkSYhqtGoDAVn2S8mkcR863Z3eAA","holderLink":"https://browncard.example/c/eyJhbGciOiJFUzI1NiIsImtpZCI6IkdILTIwMjYtMSJ9.eyJuIjoiR0gtMjAyNi0wMDA0NzExIn0.k3fT9Qm2","renewalOf":null,"renewedBy":null,"requestId":null,"sourceSystem":null,"issuedBy":"api_client:key:7d2c91ab-35e0-4f68-b1a4-60c8d2e9f357"}}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","errors":[{"path":"reason","message":"Invalid input: expected string, received undefined"}],"correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The certificate was issued by another insurer, or the caller lacks `certificate.duplicate`.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The certificate was issued by another insurer, or the caller lacks `certificate.duplicate`.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"Only the issuing insurer can do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"404":{"description":"Not found. The `code` in the body says which of these it is.\n\n- `NOT_FOUND`: The certificate does not exist, or belongs to another organisation.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"NOT_FOUND":{"summary":"404 NOT_FOUND","description":"The certificate does not exist, or belongs to another organisation.","value":{"type":"urn:bc:problem:not_found","title":"Not found","status":404,"code":"NOT_FOUND","detail":"the certificate was not found.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"409":{"description":"Conflict. The `code` in the body says which of these it is.\n\n- `INVALID_STATUS`: The certificate is not in force.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"INVALID_STATUS":{"summary":"409 INVALID_STATUS","description":"The certificate is not in force.","value":{"type":"urn:bc:problem:invalid_status","title":"Conflict","status":409,"code":"INVALID_STATUS","detail":"This certificate is suspended; only a certificate in force can be duplicated.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Issue a duplicate of a certificate","tags":["Issue and manage certificates"],"x-integrator":true,"x-permissions":["certificate.duplicate"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/trust-list":{"get":{"description":"Use this to check certificate QR codes in your own system without calling the platform each time. Each QR code carries a signature made with the issuing country's key; fetch the keys once, keep them, and verify the signature locally against the key named by the certificate's `keyId` (the `kid` in the code's header).\n\nThe answer is a JSON Web Key Set: one public key per issuing country and year, ES256 (ECDSA with P-256 and SHA-256). New keys appear when a country starts a new year; retired keys are dropped from this list. The answer may be cached for 24 hours.\n\nTo check the status of a certificate as well as its signature, use the verification API, which also covers suspended and cancelled certificates.\n\n**Access.** Open to everyone. No key is needed.","operationId":"getSigningKeys","parameters":[],"responses":{"200":{"description":"The public keys.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"cache-control":{"description":"May be cached for 24 hours.","schema":{"type":"string"},"example":"public, max-age=86400"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SigningKeys"},"examples":{"keys":{"summary":"Two keys","value":{"keys":[{"kty":"EC","crv":"P-256","x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU","y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0","kid":"GH-2026-1","alg":"ES256","use":"sig"},{"kty":"EC","crv":"P-256","x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4","y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM","kid":"TG-2026-1","alg":"ES256","use":"sig"}]}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests from this address. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Get the public keys that sign certificates","tags":["Signing keys"],"x-integrator":true,"x-public":true,"security":[]}},"/stock":{"get":{"description":"Use this to see how many certificates you can still issue, and what used or added credits recently. Check it before sending a large batch, or from a monitoring job that warns you when `belowThreshold` is true.\n\n`account.balance` is the number of certificates that can be issued now. `account.threshold` is the level you asked to be warned at; `belowThreshold` is true once the balance falls under it. `movements` lists the latest changes, newest first: credits added when an order is released (`RELEASED`), and one credit used for each certificate issued (`CONSUMED`).\n\nWhen the balance reaches zero, issuing is refused with `STOCK_EMPTY` until credits are ordered from the national bureau.\n\n**Access.** Send an integration key or a signed-in session. The caller needs the permission `stock.read`; choose it when you create the key under Integrations → Integration keys.","operationId":"getCertificateCredits","parameters":[{"name":"limit","in":"query","required":false,"description":"How many movements to return, from 1 to 500. Defaults to 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":500},"example":20}],"responses":{"200":{"description":"The balance, the threshold and the latest movements.","headers":{"x-correlation-id":{"description":"Identifies this call. It repeats the `x-correlation-id` you sent, or is generated. Quote it to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credits"},"examples":{"credits":{"summary":"A balance with recent use","value":{"account":{"orgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","orgName":"Volta Assurance","orgCode":"GH-VOLTA","orgType":"INSURER","country":"GH","balance":1482,"threshold":500,"belowThreshold":false,"updatedAt":"2026-10-12T08:14:04.512Z"},"movements":[{"id":"e5d2a8b4-7c13-4f60-91ab-3d8c0e6f2b57","orgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","delta":-1,"balanceAfter":1482,"reason":"CONSUMED","ref":"GH-2026-0004711","at":"2026-10-12T08:14:04.512Z"},{"id":"38b9f1c6-a042-4d7e-85c3-6e1f9a2d4b08","orgId":"0e6b3a14-52c8-5d7f-9a21-8b4f6c0d7e13","delta":2000,"balanceAfter":1483,"reason":"RELEASED","ref":"ORD-2026-0031","at":"2026-10-05T11:20:00.000Z"}]}}}}}},"400":{"description":"Bad request. The `code` in the body says which of these it is.\n\n- `VALIDATION`: A field is missing or has a value the API does not accept; `errors` lists each one.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"VALIDATION":{"summary":"400 VALIDATION","description":"A field is missing or has a value the API does not accept; `errors` lists each one.","value":{"type":"urn:bc:problem:validation","title":"Bad request","status":400,"code":"VALIDATION","detail":"Some fields are missing or invalid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"401":{"description":"Unauthorized. The `code` in the body says which of these it is.\n\n- `UNAUTHENTICATED`: The key is missing, mistyped or revoked, or the session has expired.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"UNAUTHENTICATED":{"summary":"401 UNAUTHENTICATED","description":"The key is missing, mistyped or revoked, or the session has expired.","value":{"type":"urn:bc:problem:unauthenticated","title":"Unauthorized","status":401,"code":"UNAUTHENTICATED","detail":"Your session has expired or the key is not valid.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"403":{"description":"Forbidden. The `code` in the body says which of these it is.\n\n- `FORBIDDEN`: The key was created without the permission this operation needs.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"FORBIDDEN":{"summary":"403 FORBIDDEN","description":"The key was created without the permission this operation needs.","value":{"type":"urn:bc:problem:forbidden","title":"Forbidden","status":403,"code":"FORBIDDEN","detail":"You do not have permission to do this.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}},"429":{"description":"Too many requests. The `code` in the body says which of these it is.\n\n- `RATE_LIMITED`: Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","headers":{"x-correlation-id":{"description":"Quote this to support.","schema":{"type":"string"},"example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"retry-after":{"description":"Seconds to wait before the next call.","schema":{"type":"integer"},"example":42}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"RATE_LIMITED":{"summary":"429 RATE_LIMITED","description":"Too many calls in a minute. Wait for the number of seconds in `retry-after`, then continue.","value":{"type":"urn:bc:problem:rate_limited","title":"Too many requests","status":429,"code":"RATE_LIMITED","detail":"Too many requests for this key. Try again in a minute.","correlationId":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"}}}}}}},"summary":"Get your certificate credits","tags":["Certificate credits"],"x-integrator":true,"x-permissions":["stock.read"],"security":[{"apiKey":[]},{"bearer":[]}]}},"/stock/threshold":{"put":{"operationId":"StockController_threshold","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"threshold":{"type":"integer","minimum":0,"maximum":100000000},"orgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["threshold"],"additionalProperties":false}}}},"responses":{"200":{"description":""}},"tags":["stock"],"x-permissions":["stock.threshold.manage"]}},"/paper-serials":{"post":{"operationId":"PaperController_register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"csv":{"type":"string","maxLength":5000000},"rows":{"maxItems":20000,"type":"array","items":{}},"country":{"type":"string","minLength":2,"maxLength":2}},"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["paper-serials"],"x-permissions":["certificate.paper.register"]},"get":{"operationId":"PaperController_list","parameters":[],"responses":{"200":{"description":""}},"tags":["paper-serials"],"x-permissions":["certificate.read"]}},"/requests":{"post":{"operationId":"RequestsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"kind":{"type":"string","enum":["NEW","RENEWAL"]},"insurerOrgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"registration":{"type":"string","minLength":2,"maxLength":20},"name":{"type":"string","maxLength":160},"phone":{"type":"string","minLength":6,"maxLength":30},"email":{"anyOf":[{"type":"string","maxLength":200,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"string","const":""}]},"certificateNumber":{"type":"string","maxLength":20}},"required":["kind","insurerOrgId","registration","phone"],"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["requests"],"x-public":true},"get":{"operationId":"RequestsController_list","parameters":[],"responses":{"200":{"description":""}},"tags":["requests"],"x-permissions":["request.read"]}},"/requests/{id}":{"get":{"operationId":"RequestsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["requests"],"x-permissions":["request.read"]}},"/requests/{id}/take":{"post":{"operationId":"RequestsController_take","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["requests"],"x-permissions":["request.handle"]}},"/requests/{id}/decline":{"post":{"operationId":"RequestsController_decline","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["reason"],"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["requests"],"x-permissions":["request.handle"]}},"/me/certificates":{"get":{"operationId":"MeController_mine","parameters":[],"responses":{"200":{"description":""}},"tags":["policyholder"],"x-permissions":["certificate.read"]}},"/me/certificates/link":{"post":{"operationId":"MeController_link","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"token":{}},"required":["token"],"additionalProperties":false}}}},"responses":{"201":{"description":""}},"tags":["policyholder"],"x-permissions":["certificate.read"]}}},"info":{"title":"Registry service","description":"Attestation management: vehicles, policyholders, policies, certificates, signing keys, signed QR, PDF, hidden mark, paper serials and stock credit balances.","version":"1.0.0","contact":{}},"tags":[{"name":"Issue and manage certificates","description":"Create a certificate for a policy, find it again, and change what happens to it: renew it, cancel it, or reissue it as a duplicate. Every certificate has a number such as `GH-2026-0004711`, a period of insurance and a status."},{"name":"Documents and pictures","description":"The certificate as a PDF to print or send, and as a picture of the card to show on a screen. Staff and holders see the whole card; anyone holding the number or the QR code can fetch the public picture, which leaves out the holder’s personal details."},{"name":"Certificate credits","description":"Each certificate issued uses one credit. Read the balance before a large run so that no certificate is refused for lack of credits."},{"name":"Signing keys","description":"Every certificate carries a QR code signed by the issuing country. The public keys below let any system check those signatures without calling the platform for each certificate."}],"servers":[],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"An integration key, created under Integrations → Integration keys. It looks like `bc_1a2b3c4d_…` and is shown once, when you create it."},"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"An integration key sent as `Authorization: Bearer bc_…`, or the session token of a signed-in user."}},"schemas":{"CertificatePage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CertificateSummary"}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Certificates that match, counted up to 1,000."},"totalCapped":{"description":"True when more than 1,000 certificates match and `total` stopped at 1,000.","type":"boolean"},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["items","total","limit","offset"],"description":"A page of certificates, newest first."},"CertificateSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The id to use in the other operations."},"number":{"type":"string","description":"The certificate number: country, year and a seven-digit sequence.","example":"GH-2026-0004711"},"registration":{"type":"string","description":"The registration plate, as printed.","example":"GR 4821-24"},"holderName":{"type":"string","description":"The policyholder’s name. In a list, readers other than the issuing insurer see it masked, for example `K. E****`.","example":"Kojo Essien"},"insurerOrgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"insurerName":{"type":"string","example":"Volta Assurance"},"insurerCode":{"type":"string","example":"GH-VOLTA"},"country":{"type":"string","minLength":2,"maxLength":2,"description":"The issuing country.","example":"GH"},"scope":{"type":"string","enum":["NATIONAL","ECOWAS"],"description":"`NATIONAL` covers the issuing country. `ECOWAS` covers the member states in `territories`."},"territories":{"type":"array","items":{"type":"string","minLength":2,"maxLength":2},"description":"The member states covered, as ISO 3166-1 alpha-2 codes.","example":["BJ","GH","TG"]},"kind":{"type":"string","enum":["CERTIFICATE","COVER_NOTE"]},"validFrom":{"type":"string","description":"First day covered, `YYYY-MM-DD`, UTC.","example":"2026-10-12"},"validTo":{"type":"string","description":"Last day covered, `YYYY-MM-DD`, UTC.","example":"2027-10-11"},"status":{"type":"string","enum":["ISSUED","SUSPENDED","CANCELLED","EXPIRED","REPLACED"],"description":"The status recorded for the certificate. `ISSUED`: in force when its dates allow. `SUSPENDED`: paused by the national bureau or the Secretariat. `CANCELLED`: ended by the insurer. `REPLACED`: a newer certificate for the same vehicle took its place. `EXPIRED`: the period of insurance has passed.","example":"ISSUED"},"validity":{"type":"string","enum":["VALID","EXPIRED","NOT_YET_VALID","SUSPENDED","CANCELLED","REPLACED"],"description":"What the certificate reads as today, from its status and its dates. `VALID` means a check made today would pass.","example":"VALID"},"source":{"type":"string","enum":["PORTAL","BULK","API","NATIONAL_FEED","USSD_REQUEST"],"description":"How the certificate was issued."},"issuedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","number","registration","holderName","insurerOrgId","insurerName","insurerCode","country","scope","territories","kind","validFrom","validTo","status","validity","source","issuedAt"],"description":"A certificate as listed."},"IssueCertificate":{"type":"object","properties":{"policyNumber":{"type":"string","minLength":1,"maxLength":60,"description":"Your policy reference. Printed on the certificate. Required.","example":"POL-GH-7781204"},"holder":{"type":"object","properties":{"type":{"default":"PERSON","description":"A person or a company.","type":"string","enum":["PERSON","COMPANY"]},"name":{"type":"string","minLength":1,"maxLength":160,"description":"The policyholder’s full name, or the company name. Required.","example":"Kojo Essien"},"address":{"type":"string","minLength":1,"maxLength":300,"description":"The policyholder’s address. Required: it is printed on every certificate.","example":"Spintex Road, Accra"},"phone":{"description":"International format. The holder receives the link to the certificate by SMS.","example":"+233244310001","type":"string","maxLength":30},"email":{"description":"The holder also receives the link by email.","example":"kojo.essien@example.org","type":"string","maxLength":200},"nationalId":{"description":"Where the country asks for it, for example the Ghana Card number.","example":"GHA-722145908-3","type":"string","maxLength":60},"locale":{"description":"The language of messages and documents for this holder. Defaults to English.","type":"string","enum":["en","fr","pt"]}},"required":["name","address"]},"vehicle":{"type":"object","properties":{"registration":{"type":"string","minLength":1,"maxLength":20,"description":"The registration plate as printed. Required.","example":"GR 4821-24"},"vin":{"type":"string","minLength":1,"maxLength":40,"description":"The chassis number (VIN). Required.","example":"JTNBE40K703118426"},"engineNumber":{"type":"string","minLength":1,"maxLength":40,"description":"The engine number. Required.","example":"1NZ-3492017"},"make":{"example":"Toyota","type":"string","maxLength":60},"model":{"example":"Corolla","type":"string","maxLength":60},"category":{"type":"string","enum":["CAR","TAXI","MINIBUS","BUS","TRUCK","TRAILER","MOTORCYCLE","TRICYCLE","VAN","PICKUP","TRACTOR","OTHER"],"description":"The vehicle type. Required.","example":"CAR"},"use":{"type":"string","enum":["PRIVATE","COMMERCIAL","HIRE","GOVERNMENT","MOTOR_TRADE"]}},"required":["registration","vin","engineNumber","category"]},"scope":{"type":"string","enum":["NATIONAL","ECOWAS"],"description":"`NATIONAL` covers your country only. `ECOWAS` is the Brown Card and covers the member states in `territories`.","example":"ECOWAS"},"territories":{"description":"With `ECOWAS`: the member states covered, as two-letter codes. Include your own country and at least one other. Leave out for all fifteen member states.","example":["GH","TG","BJ"],"maxItems":15,"type":"array","items":{"type":"string","minLength":2,"maxLength":2}},"kind":{"default":"CERTIFICATE","description":"A certificate runs up to two years. A cover note runs one month at most.","type":"string","enum":["CERTIFICATE","COVER_NOTE"]},"validFrom":{"type":"string","description":"First day of the period of insurance, `YYYY-MM-DD`, UTC. Required.","example":"2026-10-12"},"validTo":{"type":"string","description":"Last day of the period of insurance, `YYYY-MM-DD`, UTC, counted as covered. Required.","example":"2027-10-11"},"requestId":{"description":"The reference (`REQ-…`) of a policyholder’s request that this certificate answers.","type":"string","maxLength":40}},"required":["policyNumber","holder","vehicle","scope","validFrom","validTo"],"description":"The certificate to issue."},"Certificate":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The id to use in the other operations."},"number":{"type":"string","description":"The certificate number: country, year and a seven-digit sequence.","example":"GH-2026-0004711"},"registration":{"type":"string","description":"The registration plate, as printed.","example":"GR 4821-24"},"holderName":{"type":"string","description":"The policyholder’s name. In a list, readers other than the issuing insurer see it masked, for example `K. E****`.","example":"Kojo Essien"},"insurerOrgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"insurerName":{"type":"string","example":"Volta Assurance"},"insurerCode":{"type":"string","example":"GH-VOLTA"},"country":{"type":"string","minLength":2,"maxLength":2,"description":"The issuing country.","example":"GH"},"scope":{"type":"string","enum":["NATIONAL","ECOWAS"],"description":"`NATIONAL` covers the issuing country. `ECOWAS` covers the member states in `territories`."},"territories":{"type":"array","items":{"type":"string","minLength":2,"maxLength":2},"description":"The member states covered, as ISO 3166-1 alpha-2 codes.","example":["BJ","GH","TG"]},"kind":{"type":"string","enum":["CERTIFICATE","COVER_NOTE"]},"validFrom":{"type":"string","description":"First day covered, `YYYY-MM-DD`, UTC.","example":"2026-10-12"},"validTo":{"type":"string","description":"Last day covered, `YYYY-MM-DD`, UTC.","example":"2027-10-11"},"status":{"type":"string","enum":["ISSUED","SUSPENDED","CANCELLED","EXPIRED","REPLACED"],"description":"The status recorded for the certificate. `ISSUED`: in force when its dates allow. `SUSPENDED`: paused by the national bureau or the Secretariat. `CANCELLED`: ended by the insurer. `REPLACED`: a newer certificate for the same vehicle took its place. `EXPIRED`: the period of insurance has passed.","example":"ISSUED"},"validity":{"type":"string","enum":["VALID","EXPIRED","NOT_YET_VALID","SUSPENDED","CANCELLED","REPLACED"],"description":"What the certificate reads as today, from its status and its dates. `VALID` means a check made today would pass.","example":"VALID"},"source":{"type":"string","enum":["PORTAL","BULK","API","NATIONAL_FEED","USSD_REQUEST"],"description":"How the certificate was issued."},"issuedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Starts at 1. A duplicate under Art. 20 raises it; earlier QR codes keep verifying."},"policyId":{"type":"string"},"policyNumber":{"type":"string","example":"POL-GH-7781204"},"holder":{"type":"object","properties":{"ref":{"type":"string"},"type":{"type":"string","enum":["PERSON","COMPANY"]},"name":{"type":"string"},"address":{"nullable":true,"type":"string"},"phone":{"nullable":true,"description":"Shown to the issuing insurer only.","type":"string"},"email":{"nullable":true,"description":"Shown to the issuing insurer only.","type":"string"}},"required":["ref","type","name","address","phone","email"]},"vehicle":{"type":"object","properties":{"registration":{"type":"string"},"vin":{"nullable":true,"description":"Chassis number.","type":"string"},"engineNumber":{"nullable":true,"type":"string"},"make":{"nullable":true,"type":"string"},"model":{"nullable":true,"type":"string"},"category":{"nullable":true,"type":"string"},"use":{"nullable":true,"type":"string"}},"required":["registration","vin","engineNumber","make","model","category","use"]},"insurer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"code":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"address":{"nullable":true,"type":"string"}},"required":["id","code","name","country","address"]},"keyId":{"type":"string","description":"The signing key of the QR code. Find it in the signing-key list.","example":"GH-2026-1"},"qrUrl":{"type":"string","description":"The address the QR code on the certificate opens. Anyone can open it to check the certificate."},"holderLink":{"type":"string","description":"A link for the policyholder to open the certificate and its PDF. Send it to the holder; it is valid for 90 days and replaced when you issue a duplicate. Empty for readers other than the issuing insurer."},"renewalOf":{"nullable":true,"description":"The certificate this one renews.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"renewedBy":{"nullable":true,"description":"The number of the certificate that renewed this one.","type":"string"},"requestId":{"nullable":true,"type":"string"},"sourceSystem":{"nullable":true,"type":"string"},"issuedBy":{"nullable":true,"type":"string"},"history":{"description":"Every change, oldest first. Present when you read one certificate.","type":"array","items":{"$ref":"#/components/schemas/CertificateHistoryEntry"}},"replayed":{"description":"True when the `Idempotency-Key` matched an earlier call: this is the certificate that call issued, and nothing new was created.","type":"boolean"}},"required":["id","number","registration","holderName","insurerOrgId","insurerName","insurerCode","country","scope","territories","kind","validFrom","validTo","status","validity","source","issuedAt","version","policyId","policyNumber","holder","vehicle","insurer","keyId","qrUrl","holderLink","renewalOf","renewedBy","requestId","sourceSystem","issuedBy"],"description":"A certificate in full."},"CertificateHistoryEntry":{"type":"object","properties":{"action":{"type":"string","enum":["ISSUED","RENEWED","DUPLICATED","SUSPENDED","REINSTATED","CANCELLED","EXPIRED","REPLACED"]},"reason":{"nullable":true,"type":"string"},"actor":{"nullable":true,"description":"Who did it: a user, an integration key or the platform.","type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"statusAfter":{"nullable":true,"type":"string","enum":["ISSUED","SUSPENDED","CANCELLED","EXPIRED","REPLACED"],"description":"The status recorded for the certificate. `ISSUED`: in force when its dates allow. `SUSPENDED`: paused by the national bureau or the Secretariat. `CANCELLED`: ended by the insurer. `REPLACED`: a newer certificate for the same vehicle took its place. `EXPIRED`: the period of insurance has passed.","example":"ISSUED"}},"required":["action","reason","actor","at","version","statusAfter"],"description":"One change in the life of a certificate."},"RenewCertificate":{"type":"object","properties":{"validFrom":{"description":"First day of the new period, `YYYY-MM-DD`, UTC. Defaults to the day after the old period ends.","example":"2027-10-12","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"validTo":{"description":"Last day of the new period. Defaults to one year (one month for a cover note) after the start.","example":"2028-10-11","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"kind":{"description":"Defaults to the kind of the certificate being renewed.","type":"string","enum":["CERTIFICATE","COVER_NOTE"]}},"description":"The new period, when it differs from the default."},"CancelCertificate":{"type":"object","properties":{"reason":{"type":"string","minLength":3,"maxLength":500,"description":"Why the certificate is cancelled, 3 to 500 characters. Kept in its history.","example":"Policy cancelled at the policyholder’s request"}},"required":["reason"],"description":"The reason for cancelling."},"DuplicateCertificate":{"type":"object","properties":{"reason":{"description":"Why a duplicate is needed. Kept in the history.","example":"Certificate lost; holder asked for a copy","type":"string","maxLength":500}},"description":"An optional reason."},"SigningKeys":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"kid":{"type":"string","example":"GH-2026-1"},"kty":{"type":"string","example":"EC"},"crv":{"type":"string","example":"P-256"},"x":{"type":"string"},"y":{"type":"string"},"alg":{"type":"string","example":"ES256"},"use":{"type":"string","example":"sig"}},"required":["kid","kty","crv","x","y","alg","use"],"description":"A public key in JSON Web Key form."}}},"required":["keys"],"description":"Public keys that verify certificate QR codes."},"Credits":{"type":"object","properties":{"account":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CreditAccount"}]},"movements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"orgId":{"type":"string"},"delta":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Credits added (positive) or used (negative)."},"balanceAfter":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"reason":{"type":"string","enum":["OPENING","RELEASED","MOVED_IN","MOVED_OUT","CONSUMED","RETURNED"]},"ref":{"nullable":true,"description":"The certificate or order the movement belongs to.","type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","orgId","delta","balanceAfter","reason","ref","at"]},"description":"The latest movements, newest first."}},"required":["account","movements"],"description":"The balance and the latest movements."},"CreditAccount":{"type":"object","properties":{"orgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"orgName":{"nullable":true,"type":"string"},"orgCode":{"nullable":true,"type":"string"},"orgType":{"nullable":true,"type":"string"},"country":{"nullable":true,"type":"string"},"balance":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Certificates that can still be issued."},"threshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The balance at which you want to be told to order more."},"belowThreshold":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["orgId","orgName","orgCode","orgType","country","balance","threshold","belowThreshold","updatedAt"],"description":"The certificate credits of one organisation."},"Problem":{"type":"object","description":"An error, as RFC 9457 problem details. Show `detail` to people; branch on `code` in code.","required":["type","title","status","code","detail","correlationId"],"properties":{"type":{"type":"string","description":"Identifies the kind of problem: `urn:bc:problem:` followed by `code` in lower case.","example":"urn:bc:problem:stock_empty"},"title":{"type":"string","description":"The name of the HTTP status.","example":"Conflict"},"status":{"type":"integer","description":"The HTTP status.","example":409},"code":{"type":"string","description":"A stable machine-readable code. Codes are never reused for another meaning.","example":"STOCK_EMPTY"},"detail":{"type":"string","description":"A plain sentence that can be shown to a person.","example":"No certificate credits are left."},"correlationId":{"type":"string","description":"Quote this when you contact support. The same value is in the `x-correlation-id` response header.","example":"9f2b1c64-3d0e-4a57-b8c1-6e7d5a0f4b21"},"errors":{"type":"array","description":"Present on validation errors: one entry per field that needs attention.","items":{"type":"object","required":["path","message"],"properties":{"path":{"type":"string","description":"The field, for example `holder.address`."},"message":{"type":"string","description":"What to correct."}}}}}}}}}